Skip to content

Commit 90b6c04

Browse files
committed
Implement inverse hyperbolic functions(asinh, acosh, atanh)
1 parent ad7a103 commit 90b6c04

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
# sinh (x, prec)
1818
# cosh (x, prec)
1919
# tanh (x, prec)
20+
# asinh(x, prec)
21+
# acosh(x, prec)
22+
# atanh(x, prec)
2023
# PI (prec)
2124
# E (prec) == exp(1.0,prec)
2225
#
@@ -435,6 +438,68 @@ def tanh(x, prec)
435438
(e - einv).div(e + einv, prec)
436439
end
437440

441+
# call-seq:
442+
# asinh(decimal, numeric) -> BigDecimal
443+
#
444+
# Computes the inverse hyperbolic sine of +decimal+ to the specified number of digits of
445+
# precision, +numeric+.
446+
#
447+
# If +decimal+ is NaN, returns NaN.
448+
#
449+
# BigMath.asinh(BigDecimal('1'), 16).to_s
450+
# #=> "0.881373587019543025232609324892919887466177636058e0"
451+
#
452+
def asinh(x, prec)
453+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
454+
return x if x.nan? || x.infinite?
455+
return -asinh(-x, prec) if x < 0
456+
457+
sqrt_prec = prec + [-x.exponent, 0].max
458+
BigMath.log(x + sqrt(x**2 + 1, sqrt_prec), prec)
459+
end
460+
461+
# call-seq:
462+
# acosh(decimal, numeric) -> BigDecimal
463+
#
464+
# Computes the inverse hyperbolic cosine of +decimal+ to the specified number of digits of
465+
# precision, +numeric+.
466+
#
467+
# If +decimal+ is NaN, returns NaN.
468+
#
469+
# BigMath.acosh(BigDecimal('2'), 16).to_s
470+
# #=> "0.1316957896924816708625046347239934461496535769096e1"
471+
#
472+
def acosh(x, prec)
473+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
474+
raise Math::DomainError, "Out of domain argument for acosh" if x < 1
475+
return BigDecimal::INFINITY if x.infinite?
476+
return BigDecimal::NAN if x.nan?
477+
478+
BigMath.log(x + sqrt(x**2 - 1, prec), prec)
479+
end
480+
481+
# call-seq:
482+
# atanh(decimal, numeric) -> BigDecimal
483+
#
484+
# Computes the inverse hyperbolic tangent of +decimal+ to the specified number of digits of
485+
# precision, +numeric+.
486+
#
487+
# If +decimal+ is NaN, returns NaN.
488+
#
489+
# BigMath.atanh(BigDecimal('0.5'), 16).to_s
490+
# #=> "0.54930614433405484569762261846126e0"
491+
#
492+
def atanh(x, prec)
493+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
494+
raise Math::DomainError, "Out of domain argument for atanh" if x < -1 || x > 1
495+
return BigDecimal::NAN if x.nan?
496+
return BigDecimal::INFINITY if x == 1
497+
return -BigDecimal::INFINITY if x == -1
498+
499+
prec += BigDecimal.double_fig
500+
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)).div(2, prec)
501+
end
502+
438503
# call-seq:
439504
# PI(numeric) -> BigDecimal
440505
#

test/bigdecimal/test_bigmath.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,52 @@ def test_hyperbolic
226226
end
227227
end
228228

229+
def test_asinh
230+
[-3, 0.5, 10].each do |x|
231+
assert_in_delta(Math.asinh(x), asinh(BigDecimal(x.to_s), N))
232+
end
233+
assert_equal(0, asinh(BigDecimal(0), N))
234+
assert_equal(PINF, asinh(PINF, N))
235+
assert_equal(MINF, asinh(MINF, N))
236+
237+
x = BigDecimal(1) / 7
238+
assert_in_delta(x, sinh(asinh(x, 100), 100), BigDecimal("1e-100"))
239+
240+
["1e-30", "0.2", "10", "100"].each do |x|
241+
assert_relative_precision {|n| asinh(BigDecimal(x), n)}
242+
end
243+
end
244+
245+
def test_acosh
246+
[1.5, 2, 10].each do |x|
247+
assert_in_delta(Math.acosh(x), acosh(BigDecimal(x.to_s), N))
248+
end
249+
assert_equal(0, acosh(BigDecimal(1), N))
250+
assert_equal(PINF, acosh(PINF, N))
251+
252+
x = BigDecimal(8) / 7
253+
assert_in_delta(x, cosh(acosh(x, 100), 100), BigDecimal("1e-100"))
254+
255+
["1." + "0" * 30 + "1", "1.5", "2", "100"].each do |x|
256+
assert_relative_precision {|n| acosh(BigDecimal(x), n)}
257+
end
258+
end
259+
260+
def test_atanh
261+
[-0.5, 0.1, 0.9].each do |x|
262+
assert_in_delta(Math.atanh(x), atanh(BigDecimal(x.to_s), N))
263+
end
264+
assert_equal(0, atanh(BigDecimal(0), N))
265+
assert_equal(PINF, atanh(BigDecimal(1), N))
266+
267+
x = BigDecimal(1) / 7
268+
assert_in_delta(x, tanh(atanh(x, 100), 100), BigDecimal("1e-100"))
269+
270+
["1e-30", "0.5", "0.9" + "9" * 30].each do |x|
271+
assert_relative_precision {|n| atanh(BigDecimal(x), n)}
272+
end
273+
end
274+
229275
def test_log
230276
assert_equal(0, BigMath.log(BigDecimal("1.0"), 10))
231277
assert_in_epsilon(Math.log(10)*1000, BigMath.log(BigDecimal("1e1000"), 10))

0 commit comments

Comments
 (0)