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 |