Skip to content

Commit 965efea

Browse files
committed
Implement inverse hyperbolic functions(asinh, acosh, atanh)
1 parent 5604c75 commit 965efea

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
#
@@ -408,6 +411,68 @@ def tanh(x, prec)
408411
(e - einv).div(e + einv, prec)
409412
end
410413

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

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)