CrackedRuby logo

CrackedRuby

Hyperbolic Functions

Ruby hyperbolic functions provide mathematical operations for sinh, cosh, tanh, and their inverse operations through the Math module.

Core Modules Math Module
3.4.5

Overview

Ruby implements hyperbolic functions through the Math module, providing both forward and inverse hyperbolic operations. The Math module defines six primary hyperbolic methods: sinh, cosh, tanh, asinh, acosh, and atanh. These functions operate on numeric values and return floating-point results.

Hyperbolic functions relate to exponential functions and appear frequently in calculus, physics, and engineering applications. Ruby's implementation follows IEEE 754 standards for floating-point arithmetic and handles special cases like infinity and NaN values according to mathematical conventions.

The forward hyperbolic functions (sinh, cosh, tanh) accept any real number input and return floating-point values. The inverse functions (asinh, acosh, atanh) have specific domain restrictions that Ruby enforces through return value handling.

Math.sinh(1.0)  # => 1.1752011936438014
Math.cosh(1.0)  # => 1.5430806348152437
Math.tanh(1.0)  # => 0.7615941559557649

Ruby converts integer inputs to floating-point values automatically, maintaining precision throughout calculations. The Math module functions are defined as singleton methods, accessible without instantiation.

# Integer inputs convert automatically
Math.sinh(2)    # => 3.6268604078470186
Math.cosh(0)    # => 1.0

Basic Usage

The Math.sinh method calculates the hyperbolic sine of a number using the formula (e^x - e^-x) / 2. This function grows exponentially for positive inputs and approaches zero asymptotically for large negative inputs.

# Basic sinh calculations
Math.sinh(0)     # => 0.0
Math.sinh(1)     # => 1.1752011936438014
Math.sinh(-1)    # => -1.1752011936438014
Math.sinh(2.5)   # => 6.0502044810397875

The Math.cosh method computes hyperbolic cosine using (e^x + e^-x) / 2. Unlike sine, cosh produces symmetric results for positive and negative inputs, with a minimum value of 1.0 at zero.

# Basic cosh calculations
Math.cosh(0)     # => 1.0
Math.cosh(1)     # => 1.5430806348152437
Math.cosh(-1)    # => 1.5430806348152437
Math.cosh(3.0)   # => 10.067661995777765

The Math.tanh method returns hyperbolic tangent, calculated as sinh(x) / cosh(x). This function approaches 1 for large positive values and -1 for large negative values, making it useful for activation functions in neural networks.

# Basic tanh calculations  
Math.tanh(0)     # => 0.0
Math.tanh(1)     # => 0.7615941559557649
Math.tanh(-1)    # => -0.7615941559557649
Math.tanh(10)    # => 0.9999999958776927

Inverse hyperbolic functions reverse these operations. The Math.asinh method accepts any real number and returns the value whose hyperbolic sine equals the input.

# Inverse hyperbolic sine
Math.asinh(0)                    # => 0.0
Math.asinh(1.1752011936438014)   # => 1.0
Math.asinh(-5.0)                 # => -2.3124383412727525

The Math.acosh method requires input values greater than or equal to 1.0, since cosh never produces values less than 1.0. Input values outside this domain return NaN.

# Inverse hyperbolic cosine
Math.acosh(1.0)                  # => 0.0
Math.acosh(1.5430806348152437)   # => 1.0
Math.acosh(2.0)                  # => 1.3169578969248166

The Math.atanh method accepts values between -1 and 1 exclusive, returning NaN for values outside this range and infinity for inputs of exactly ±1.

# Inverse hyperbolic tangent
Math.atanh(0)                    # => 0.0
Math.atanh(0.5)                  # => 0.5493061443340549
Math.atanh(0.7615941559557649)   # => 1.0

Error Handling & Debugging

Hyperbolic functions handle invalid inputs by returning special floating-point values rather than raising exceptions. Understanding these return patterns prevents logical errors in mathematical computations.

The Math.acosh method returns NaN when input values fall below 1.0, since the mathematical domain of inverse hyperbolic cosine excludes these values.

# Domain violations return NaN
Math.acosh(0.5)   # => NaN
Math.acosh(-1.0)  # => NaN

# Check for NaN results
result = Math.acosh(0.8)
if result.nan?
  puts "Input outside valid domain"
end

The Math.atanh method exhibits different behavior at domain boundaries. Values outside the range (-1, 1) return NaN, while the boundary values ±1 return ±Infinity.

# Boundary behavior for atanh
Math.atanh(1.0)    # => Infinity
Math.atanh(-1.0)   # => -Infinity
Math.atanh(1.1)    # => NaN
Math.atanh(-1.5)   # => NaN

# Validate input ranges
def safe_atanh(x)
  return nil if x.abs >= 1.0
  Math.atanh(x)
end

safe_atanh(0.9)   # => 1.4722194895832204
safe_atanh(1.0)   # => nil

Floating-point precision limits affect hyperbolic calculations, particularly for large input values where exponential growth causes overflow conditions.

# Large values produce infinity
Math.sinh(1000)   # => Infinity
Math.cosh(1000)   # => Infinity
Math.tanh(1000)   # => 1.0 (approaches asymptote)

# Check for infinite results
def bounded_sinh(x)
  result = Math.sinh(x)
  result.infinite? ? nil : result
end

bounded_sinh(50)     # => 5.343237290762231e+21
bounded_sinh(1000)   # => nil

Input type validation prevents unexpected behavior when non-numeric values reach hyperbolic functions. Ruby's automatic type conversion handles most cases, but explicit validation improves error messaging.

# Type validation wrapper
def validated_sinh(value)
  numeric_value = Float(value)
  Math.sinh(numeric_value)
rescue TypeError, ArgumentError => e
  raise ArgumentError, "Invalid input for sinh: #{value.inspect}"
end

validated_sinh("2.5")    # => 6.0502044810397875
validated_sinh(nil)      # => ArgumentError

Complex mathematical operations combining multiple hyperbolic functions require careful handling of intermediate NaN or infinite values to prevent error propagation.

# Composite calculation with error checking
def hyperbolic_identity_check(x)
  cosh_val = Math.cosh(x)
  sinh_val = Math.sinh(x)
  
  return nil if cosh_val.nan? || sinh_val.nan?
  return nil if cosh_val.infinite? || sinh_val.infinite?
  
  # cosh²(x) - sinh²(x) should equal 1
  result = cosh_val**2 - sinh_val**2
  (result - 1.0).abs < 1e-10
end

hyperbolic_identity_check(2.0)    # => true
hyperbolic_identity_check(1000)   # => nil (overflow)

Performance & Memory

Hyperbolic function calculations involve exponential operations that scale differently across input ranges. Understanding performance characteristics helps optimize mathematical code using these functions.

The forward hyperbolic functions (sinh, cosh, tanh) demonstrate varying computational complexity. The tanh function often performs faster than separate sinh and cosh calculations due to optimized implementations.

require 'benchmark'

# Performance comparison for different ranges
small_values = (1..1000).map { |i| i * 0.01 }
large_values = (1..1000).map { |i| i * 0.1 }

Benchmark.bmbm do |x|
  x.report("sinh small") { small_values.each { |v| Math.sinh(v) } }
  x.report("cosh small") { small_values.each { |v| Math.cosh(v) } }
  x.report("tanh small") { small_values.each { |v| Math.tanh(v) } }
  
  x.report("sinh large") { large_values.each { |v| Math.sinh(v) } }
  x.report("cosh large") { large_values.each { |v| Math.cosh(v) } }
  x.report("tanh large") { large_values.each { |v| Math.tanh(v) } }
end

Inverse hyperbolic functions require iterative algorithms or logarithmic calculations, making them computationally more expensive than forward functions. Cache frequently used inverse calculations when processing large datasets.

# Caching strategy for expensive inverse calculations
class HyperbolicCache
  def initialize
    @asinh_cache = {}
    @acosh_cache = {}
    @atanh_cache = {}
  end
  
  def cached_asinh(x)
    @asinh_cache[x] ||= Math.asinh(x)
  end
  
  def cached_acosh(x)
    return Float::NAN if x < 1.0
    @acosh_cache[x] ||= Math.acosh(x)
  end
  
  def cached_atanh(x)
    return Float::NAN if x.abs >= 1.0
    @atanh_cache[x] ||= Math.atanh(x)
  end
end

cache = HyperbolicCache.new
# Subsequent calls use cached values
cache.cached_asinh(5.0)  # Calculates and stores
cache.cached_asinh(5.0)  # Returns cached value

Memory allocation patterns differ between hyperbolic functions and basic arithmetic operations. Each function call allocates floating-point objects, which accumulates in memory-intensive calculations.

# Memory-efficient batch processing
def process_hyperbolic_batch(values, function_symbol)
  # Process in chunks to manage memory
  chunk_size = 10_000
  results = []
  
  values.each_slice(chunk_size) do |chunk|
    chunk_results = chunk.map { |v| Math.send(function_symbol, v) }
    results.concat(chunk_results)
    GC.start if results.size % 50_000 == 0
  end
  
  results
end

large_dataset = (1..100_000).map { |i| i * 0.001 }
sinh_results = process_hyperbolic_batch(large_dataset, :sinh)

Vectorizing hyperbolic operations across arrays reduces method call overhead compared to iterative approaches. Consider using array methods that minimize intermediate object creation.

# Efficient array processing
module HyperbolicArray
  def self.sinh_array(values)
    values.map! { |x| Math.sinh(x) }
  end
  
  def self.parallel_hyperbolic(values)
    # Split array for potential parallel processing
    mid = values.size / 2
    left_half = values[0...mid]
    right_half = values[mid..-1]
    
    [
      left_half.map { |x| Math.sinh(x) },
      right_half.map { |x| Math.cosh(x) }
    ].flatten
  end
end

Reference

Forward Hyperbolic Functions

Method Parameters Returns Description
Math.sinh(x) x (Numeric) Float Hyperbolic sine: (e^x - e^-x) / 2
Math.cosh(x) x (Numeric) Float Hyperbolic cosine: (e^x + e^-x) / 2
Math.tanh(x) x (Numeric) Float Hyperbolic tangent: sinh(x) / cosh(x)

Inverse Hyperbolic Functions

Method Parameters Returns Description
Math.asinh(x) x (Numeric) Float Inverse hyperbolic sine, domain: all reals
Math.acosh(x) x (Numeric) Float Inverse hyperbolic cosine, domain: x ≥ 1
Math.atanh(x) x (Numeric) Float Inverse hyperbolic tangent, domain: -1 < x < 1

Domain and Range Specifications

Function Domain Range Special Values
sinh (-∞, +∞) (-∞, +∞) sinh(0) = 0
cosh (-∞, +∞) [1, +∞) cosh(0) = 1
tanh (-∞, +∞) (-1, +1) tanh(0) = 0
asinh (-∞, +∞) (-∞, +∞) asinh(0) = 0
acosh [1, +∞) [0, +∞) acosh(1) = 0
atanh (-1, +1) (-∞, +∞) atanh(0) = 0

Error Conditions and Return Values

Condition Method Input Return Value
Domain violation acosh x < 1.0 NaN
Domain violation atanh |x| > 1.0 NaN
Boundary value atanh x = ±1.0 ±Infinity
Overflow sinh, cosh |x| > ~710 ±Infinity
Underflow All functions Very small inputs Approaches 0.0

Mathematical Identities

Identity Ruby Implementation
cosh²(x) - sinh²(x) = 1 Math.cosh(x)**2 - Math.sinh(x)**2
tanh(x) = sinh(x) / cosh(x) Math.sinh(x) / Math.cosh(x)
sinh(2x) = 2·sinh(x)·cosh(x) 2 * Math.sinh(x) * Math.cosh(x)
cosh(2x) = cosh²(x) + sinh²(x) Math.cosh(x)**2 + Math.sinh(x)**2

Input Type Handling

Input Type Conversion Example
Integer Automatic to Float Math.sinh(2) # => 3.626...
Float Direct processing Math.sinh(2.0) # => 3.626...
Rational Convert to Float Math.sinh(Rational(1,2)) # => 0.521...
Complex Not supported Raises TypeError
String Not supported Raises TypeError

Performance Characteristics

Operation Relative Speed Memory Usage Notes
sinh Fast Low Exponential calculation
cosh Fast Low Exponential calculation
tanh Fast Low Often optimized implementation
asinh Medium Low Logarithmic calculation
acosh Medium Low Logarithmic calculation
atanh Slow Low Complex iterative algorithm