CrackedRuby logo

CrackedRuby

Trigonometric Functions

Ruby trigonometric functions provide mathematical operations for calculating sine, cosine, tangent, and related inverse functions through the Math module.

Core Modules Math Module
3.4.1

Overview

Ruby's Math module contains trigonometric functions that operate on floating-point numbers representing angles in radians. The module includes basic trigonometric functions (sin, cos, tan), their inverse counterparts (asin, acos, atan), and hyperbolic variants (sinh, cosh, tanh). All trigonometric functions expect radian input and return floating-point results.

The Math module provides mathematical constants including Math::PI for pi calculations and Math::E for natural logarithm operations. These constants integrate with trigonometric functions for precise angle calculations and unit conversions.

Math.sin(Math::PI / 2)
# => 1.0

Math.cos(0)
# => 1.0

Math.tan(Math::PI / 4)
# => 1.0

Ruby implements trigonometric functions using the underlying C math library, providing IEEE 754 floating-point precision. The functions handle special values according to mathematical conventions, returning NaN for undefined operations and infinity for operations that exceed floating-point bounds.

Math.sin(0)
# => 0.0

Math.asin(2)  # Domain error - input outside [-1, 1]
# => NaN

Math.tan(Math::PI / 2)  # Approaches infinity
# => 1.633123935319537e+16

The trigonometric functions integrate with Ruby's numeric types, accepting Integer, Float, Rational, and Complex inputs. Integer and Rational inputs undergo automatic conversion to Float before calculation, while Complex inputs return Complex results.

Basic Usage

Ruby trigonometric functions operate through the Math module using standard mathematical notation. The sin, cos, and tan functions accept angle measurements in radians and return floating-point results between -1 and 1 for sine and cosine, with tangent having an unlimited range.

# Basic trigonometric calculations
angle = Math::PI / 6  # 30 degrees in radians
Math.sin(angle)
# => 0.49999999999999994

Math.cos(angle)
# => 0.8660254037844387

Math.tan(angle)
# => 0.5773502691896257

Converting between degrees and radians requires multiplication with Math::PI. Ruby does not provide built-in degree-to-radian conversion methods, requiring manual calculation for degree-based inputs.

def degrees_to_radians(degrees)
  degrees * Math::PI / 180.0
end

def radians_to_degrees(radians)
  radians * 180.0 / Math::PI
end

# Calculate sine of 45 degrees
angle_degrees = 45
angle_radians = degrees_to_radians(angle_degrees)
Math.sin(angle_radians)
# => 0.7071067811865475

Inverse trigonometric functions (asin, acos, atan) calculate angles from ratio values. These functions return results in radians within specific ranges: asin and acos return values between -π/2 and π/2, while acos returns values between 0 and π.

# Inverse trigonometric functions
ratio = 0.5
Math.asin(ratio)
# => 0.5235987755982989  # π/6 radians (30 degrees)

Math.acos(ratio)
# => 1.0471975511965979  # π/3 radians (60 degrees)

Math.atan(ratio)
# => 0.4636476090008061  # ~26.57 degrees

The atan2 function calculates arctangent using both x and y coordinates, providing full 360-degree range results and handling zero denominators correctly. This function proves essential for coordinate system calculations and angle determination from vector components.

# atan2 for full quadrant angle calculation
x, y = 1, 1
Math.atan2(y, x)
# => 0.7853981633974483  # π/4 radians (45 degrees)

# Different quadrants produce different results
Math.atan2(-1, 1)   # Fourth quadrant
# => -0.7853981633974483

Math.atan2(1, -1)   # Second quadrant  
# => 2.356194490192345

Advanced Usage

Complex number trigonometric calculations extend Ruby's Math functions beyond real number domains. Ruby automatically handles complex inputs for trigonometric functions, returning complex results that maintain mathematical relationships.

require 'complex'

# Complex trigonometric calculations
z = Complex(1, 1)
Math.sin(z)
# => (1.2984575814159773+0.6349639147847361i)

Math.cos(z) 
# => (0.8337300251311491-0.9888977057628651i)

# Euler's formula verification: e^(ix) = cos(x) + i*sin(x)
x = Math::PI / 4
euler_result = Math::E ** Complex(0, x)
trig_result = Complex(Math.cos(x), Math.sin(x))
(euler_result - trig_result).abs < 1e-15
# => true

Hyperbolic trigonometric functions (sinh, cosh, tanh) calculate hyperbolic ratios using exponential relationships. These functions find applications in engineering calculations, physics modeling, and mathematical analysis requiring hyperbolic geometry.

# Hyperbolic trigonometric functions
x = 1.0
Math.sinh(x)
# => 1.1752011936438014

Math.cosh(x)
# => 1.5430806348152437

Math.tanh(x)
# => 0.7615941559557649

# Hyperbolic identity verification: cosh²(x) - sinh²(x) = 1
cosh_x = Math.cosh(x)
sinh_x = Math.sinh(x)
identity_result = cosh_x**2 - sinh_x**2
(identity_result - 1.0).abs < 1e-15
# => true

Trigonometric function composition creates complex mathematical expressions for specialized calculations. Combining multiple trigonometric operations enables advanced geometric computations and mathematical modeling.

# Complex trigonometric composition
def calculate_wave_interference(amplitude1, freq1, amplitude2, freq2, time)
  wave1 = amplitude1 * Math.sin(2 * Math::PI * freq1 * time)
  wave2 = amplitude2 * Math.sin(2 * Math::PI * freq2 * time)
  wave1 + wave2
end

# Calculate interference pattern
time_points = (0..100).map { |t| t / 100.0 }
interference_pattern = time_points.map do |t|
  calculate_wave_interference(1.0, 2.0, 0.5, 3.0, t)
end

# Find maximum interference amplitude
max_amplitude = interference_pattern.max
# => 1.4999999999999998

Series expansions and iterative calculations using trigonometric functions enable numerical analysis applications. Taylor series implementations provide custom precision control and mathematical approximation capabilities.

# Taylor series approximation for sine function
def sine_taylor_series(x, terms = 10)
  result = 0.0
  (0...terms).each do |n|
    term = ((-1)**n) * (x**(2*n + 1)) / factorial(2*n + 1)
    result += term
  end
  result
end

def factorial(n)
  return 1 if n <= 1
  (2..n).reduce(:*)
end

# Compare Taylor series with Math.sin
angle = Math::PI / 6
taylor_result = sine_taylor_series(angle)
math_result = Math.sin(angle)
error = (taylor_result - math_result).abs
# => 1.9539925233402755e-14

Error Handling & Debugging

Domain errors occur when trigonometric functions receive inputs outside their valid ranges. Inverse trigonometric functions asin and acos accept inputs only between -1 and 1, returning NaN for values outside this domain.

# Domain error handling for inverse functions
def safe_asin(value)
  if value.abs > 1
    puts "Warning: asin domain error for value #{value}"
    return Float::NAN
  end
  Math.asin(value)
end

safe_asin(1.5)
# Warning: asin domain error for value 1.5
# => NaN

# Check for NaN results
result = Math.asin(2.0)
if result.nan?
  puts "Invalid result: domain error occurred"
end
# Invalid result: domain error occurred

Floating-point precision limitations create rounding errors in trigonometric calculations. These errors accumulate through repeated operations and require explicit handling for critical applications.

# Precision error demonstration
angle = Math::PI / 3
calculated_cos = Math.cos(angle)
expected_cos = 0.5

# Direct comparison fails due to floating-point precision
calculated_cos == expected_cos
# => false

# Use epsilon comparison for floating-point equality
def float_equal?(a, b, epsilon = 1e-12)
  (a - b).abs < epsilon
end

float_equal?(calculated_cos, expected_cos)
# => true

# Accumulated precision errors in iterative calculations
sum = 0.0
1000.times do |i|
  sum += Math.sin(i * 0.01)
end
# Result may contain accumulated floating-point errors

Range validation prevents invalid inputs from propagating through calculations. Custom wrapper functions provide input sanitization and meaningful error messages for application-specific requirements.

class TrigCalculator
  def self.safe_sin(angle, max_magnitude = 1000)
    if angle.abs > max_magnitude
      raise ArgumentError, "Angle magnitude #{angle.abs} exceeds maximum #{max_magnitude}"
    end
    
    normalized_angle = angle % (2 * Math::PI)
    Math.sin(normalized_angle)
  end
  
  def self.degrees_sin(degrees)
    if !degrees.is_a?(Numeric)
      raise TypeError, "Expected numeric input, got #{degrees.class}"
    end
    
    radians = degrees * Math::PI / 180.0
    safe_sin(radians)
  end
end

# Error handling examples
begin
  TrigCalculator.degrees_sin("45")
rescue TypeError => e
  puts "Type error: #{e.message}"
end
# Type error: Expected numeric input, got String

begin
  TrigCalculator.safe_sin(10000)
rescue ArgumentError => e
  puts "Range error: #{e.message}" 
end
# Range error: Angle magnitude 10000.0 exceeds maximum 1000

Debugging trigonometric calculations requires understanding mathematical properties and floating-point representation. Identity verification helps validate calculation correctness and detect numerical instabilities.

# Debugging helper methods
module TrigDebugger
  def self.verify_identity(angle, tolerance = 1e-12)
    sin_val = Math.sin(angle)
    cos_val = Math.cos(angle)
    
    # Fundamental identity: sin²(x) + cos²(x) = 1
    identity_result = sin_val**2 + cos_val**2
    identity_error = (identity_result - 1.0).abs
    
    puts "Angle: #{angle}"
    puts "sin(x): #{sin_val}"
    puts "cos(x): #{cos_val}"
    puts "sin²(x) + cos²(x): #{identity_result}"
    puts "Identity error: #{identity_error}"
    puts "Identity valid: #{identity_error < tolerance}"
    
    identity_error < tolerance
  end
  
  def self.angle_info(radians)
    degrees = radians * 180.0 / Math::PI
    quadrant = case
               when radians >= 0 && radians < Math::PI / 2 then 1
               when radians >= Math::PI / 2 && radians < Math::PI then 2
               when radians >= Math::PI && radians < 3 * Math::PI / 2 then 3
               else 4
               end
    
    puts "Radians: #{radians}"
    puts "Degrees: #{degrees}" 
    puts "Quadrant: #{quadrant}"
  end
end

# Debug trigonometric calculations
TrigDebugger.verify_identity(Math::PI / 4)
TrigDebugger.angle_info(Math::PI / 4)

Common Pitfalls

Radian versus degree confusion represents the most frequent error in trigonometric calculations. Ruby expects radian inputs for all trigonometric functions, but many applications work with degree measurements, creating conversion requirement.

# Common degree/radian confusion
angle_degrees = 90

# Wrong: treating degrees as radians
wrong_result = Math.sin(angle_degrees)
# => 0.8939966636005579  # sin(90 radians), not sin(90°)

# Correct: convert degrees to radians first  
correct_radians = angle_degrees * Math::PI / 180.0
correct_result = Math.sin(correct_radians)
# => 1.0  # sin(90°) = 1

# Helper method prevents confusion
def sin_degrees(degrees)
  Math.sin(degrees * Math::PI / 180.0)
end

sin_degrees(90)
# => 1.0

Floating-point precision issues cause unexpected results when comparing trigonometric outputs. Mathematical identities that should produce exact results often contain small errors due to binary floating-point representation.

# Precision pitfall in trigonometric identities
angle = Math::PI / 6

# Expected: sin(π/6) = 0.5 exactly
sin_result = Math.sin(angle)
sin_result == 0.5
# => false  # Due to floating-point precision

sin_result
# => 0.49999999999999994

# Safe comparison using epsilon
def approximately_equal?(a, b, epsilon = 1e-12)
  (a - b).abs < epsilon
end

approximately_equal?(sin_result, 0.5)
# => true

# Identity verification with precision tolerance
angle = Math::PI / 4
sin_val = Math.sin(angle)
cos_val = Math.cos(angle)
identity_sum = sin_val**2 + cos_val**2

# Direct comparison fails
identity_sum == 1.0
# => false

# Epsilon comparison succeeds  
approximately_equal?(identity_sum, 1.0)
# => true

Angle normalization problems occur with large angle inputs that exceed expected ranges. Trigonometric functions mathematically handle large inputs but may produce unexpected results due to precision loss in large number operations.

# Large angle precision loss
large_angle = 1000000 * Math::PI

# Precision loss in large angle calculations
result1 = Math.sin(large_angle)
result2 = Math.sin(large_angle + 0.001)

# Results may be unreliable due to floating-point limits
puts "sin(#{large_angle}): #{result1}"
puts "Difference with small increment: #{(result2 - result1).abs}"

# Angle normalization prevents precision issues
def normalize_angle(angle)
  normalized = angle % (2 * Math::PI)
  normalized > Math::PI ? normalized - 2 * Math::PI : normalized
end

normalized_large = normalize_angle(large_angle)
reliable_result = Math.sin(normalized_large)
# => More reliable result due to smaller input magnitude

Inverse function domain violations produce NaN results that propagate through calculations. Code must explicitly check for NaN values to prevent silent failures in mathematical computations.

# NaN propagation in calculations
def calculate_triangle_angle(opposite, hypotenuse)
  ratio = opposite / hypotenuse
  Math.asin(ratio)  # May return NaN if ratio > 1
end

# Invalid triangle creates NaN
angle = calculate_triangle_angle(10, 5)  # Invalid: opposite > hypotenuse
angle.nan?
# => true

# NaN propagates through subsequent calculations
next_calculation = Math.cos(angle)
next_calculation.nan?
# => true

# Defensive programming prevents NaN propagation
def safe_triangle_angle(opposite, hypotenuse)
  return nil if hypotenuse <= 0
  
  ratio = opposite.to_f / hypotenuse
  
  if ratio.abs > 1
    puts "Warning: Invalid triangle ratio #{ratio}"
    return nil
  end
  
  Math.asin(ratio)
end

safe_angle = safe_triangle_angle(10, 5)
# Warning: Invalid triangle ratio 2.0
# => nil

Reference

Core Trigonometric Functions

Method Parameters Returns Description
Math.sin(x) x (Numeric) Float Sine of x (x in radians)
Math.cos(x) x (Numeric) Float Cosine of x (x in radians)
Math.tan(x) x (Numeric) Float Tangent of x (x in radians)
Math.asin(x) x (Numeric) Float Arcsine of x, returns radians
Math.acos(x) x (Numeric) Float Arccosine of x, returns radians
Math.atan(x) x (Numeric) Float Arctangent of x, returns radians
Math.atan2(y, x) y, x (Numeric) Float Arctangent of y/x with quadrant handling

Hyperbolic Functions

Method Parameters Returns Description
Math.sinh(x) x (Numeric) Float Hyperbolic sine of x
Math.cosh(x) x (Numeric) Float Hyperbolic cosine of x
Math.tanh(x) x (Numeric) Float Hyperbolic tangent of x
Math.asinh(x) x (Numeric) Float Inverse hyperbolic sine of x
Math.acosh(x) x (Numeric) Float Inverse hyperbolic cosine of x
Math.atanh(x) x (Numeric) Float Inverse hyperbolic tangent of x

Mathematical Constants

Constant Value Description
Math::PI 3.141592653589793 Pi constant (π)
Math::E 2.718281828459045 Euler's number (e)

Function Domains and Ranges

Function Valid Input Domain Output Range
sin(x) All real numbers [-1, 1]
cos(x) All real numbers [-1, 1]
tan(x) x ≠ (π/2 + nπ) All real numbers
asin(x) [-1, 1] [-π/2, π/2]
acos(x) [-1, 1] [0, π]
atan(x) All real numbers (-π/2, π/2)
atan2(y, x) All real y, x (-π, π]

Special Values and Edge Cases

Input sin cos tan Notes
0 0.0 1.0 0.0 Exact values
π/6 0.5 √3/2 1/√3 30° angle
π/4 √2/2 √2/2 1.0 45° angle
π/3 √3/2 0.5 √3 60° angle
π/2 1.0 0.0 ±∞ 90° angle, tan approaches infinity
π 0.0 -1.0 0.0 180° angle

Error Conditions

Function Error Condition Ruby Behavior
asin(x) |x| > 1 Returns NaN
acos(x) |x| > 1 Returns NaN
acosh(x) x < 1 Returns NaN
atanh(x) |x| ≥ 1 Returns ±Infinity or NaN
Math.sqrt(-1) Negative input Returns NaN

Angle Conversion Reference

# Degrees to radians
radians = degrees * Math::PI / 180.0

# Radians to degrees  
degrees = radians * 180.0 / Math::PI

# Common angle conversions
DEGREE_RADIAN_TABLE = {
  0   => 0,
  30  => Math::PI / 6,
  45  => Math::PI / 4, 
  60  => Math::PI / 3,
  90  => Math::PI / 2,
  180 => Math::PI,
  270 => 3 * Math::PI / 2,
  360 => 2 * Math::PI
}

Performance Characteristics

Operation Relative Performance Notes
sin, cos, tan Fast Direct C library calls
asin, acos, atan Medium More computationally intensive
atan2 Medium Handles quadrant logic
sinh, cosh, tanh Fast Exponential-based calculations
Complex trig functions Slower Additional complex number overhead

Thread Safety

All Math module trigonometric functions are thread-safe and reentrant. They do not modify global state and can be called concurrently from multiple threads without synchronization requirements.