Skip to content

Commit 11d0084

Browse files
committed
Implement inverse hyperbolic functions(asinh, acosh, atanh)
1 parent 062f7ad commit 11d0084

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
#
@@ -405,6 +408,68 @@ def tanh(x, prec)
405408
(e - einv).div(e + einv, prec)
406409
end
407410

411+
# call-seq:
412+
# asinh(decimal, numeric) -> BigDecimal
413+
#
414+
# Computes the inverse hyperbolic sine of +decimal+ to the specified number of digits of
415+
# precision, +numeric+.
416+
#
417+
# If +decimal+ is NaN, returns NaN.
418+
#
419+
# BigMath.asinh(BigDecimal('1'), 16).to_s
420+
# #=> "0.881373587019543025232609324892919887466177636058e0"
421+
#
422+
def asinh(x, prec)
423+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
424+
return x if x.nan? || x.infinite?
425+
return -asinh(-x, prec) if x < 0
426+
427+
sqrt_prec = prec + [-x.exponent, 0].max
428+
BigMath.log(x + sqrt(x**2 + 1, sqrt_prec), prec)
429+
end
430+
431+
# call-seq:
432+
# acosh(decimal, numeric) -> BigDecimal
433+
#
434+
# Computes the inverse hyperbolic cosine of +decimal+ to the specified number of digits of
435+
# precision, +numeric+.
436+
#
437+
# If +decimal+ is NaN, returns NaN.
438+
#
439+
# BigMath.acosh(BigDecimal('2'), 16).to_s
440+
# #=> "0.1316957896924816708625046347239934461496535769096e1"
441+
#
442+
def acosh(x, prec)
443+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
444+
raise Math::DomainError, "Out of domain argument for acosh" if x < 1
445+
return BigDecimal::INFINITY if x.infinite?
446+
return BigDecimal::NAN if x.nan?
447+
448+
BigMath.log(x + sqrt(x**2 - 1, prec), prec)
449+
end
450+
451+
# call-seq:
452+
# atanh(decimal, numeric) -> BigDecimal
453+
#
454+
# Computes the inverse hyperbolic tangent of +decimal+ to the specified number of digits of
455+
# precision, +numeric+.
456+
#
457+
# If +decimal+ is NaN, returns NaN.
458+
#
459+
# BigMath.atanh(BigDecimal('0.5'), 16).to_s
460+
# #=> "0.54930614433405484569762261846126e0"
461+
#
462+
def atanh(x, prec)
463+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
464+
raise Math::DomainError, "Out of domain argument for atanh" if x < -1 || x > 1
465+
return BigDecimal::NAN if x.nan?
466+
return BigDecimal::INFINITY if x == 1
467+
return -BigDecimal::INFINITY if x == -1
468+
469+
prec += BigDecimal.double_fig
470+
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)).div(2, prec)
471+
end
472+
408473
# call-seq:
409474
# PI(numeric) -> BigDecimal
410475
#

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_exp
230276
[-100, -2, 0.5, 10, 100].each do |x|
231277
assert_in_epsilon(Math.exp(x), BigMath.exp(BigDecimal(x, 0), N))

0 commit comments

Comments
 (0)