Skip to content

Commit de9072b

Browse files
committed
Implement inverse hyperbolic functions(asinh, acosh, atanh)
1 parent 04162f0 commit de9072b

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 64 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
#
@@ -421,6 +424,67 @@ def tanh(x, prec)
421424
(e - einv).div(e + einv, prec)
422425
end
423426

427+
# call-seq:
428+
# asinh(decimal, numeric) -> BigDecimal
429+
#
430+
# Computes the inverse hyperbolic sine of +decimal+ to the specified number of digits of
431+
# precision, +numeric+.
432+
#
433+
# If +decimal+ is NaN, returns NaN.
434+
#
435+
# BigMath.asinh(BigDecimal('1'), 16).to_s
436+
# #=> "0.881373587019543025232609324892919887466177636058e0"
437+
#
438+
def asinh(x, prec)
439+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
440+
return x if x.nan? || x.infinite?
441+
return -asinh(-x, prec) if x < 0
442+
BigMath.log(x + sqrt(x ** 2 + 1, prec), prec)
443+
end
444+
445+
# call-seq:
446+
# acosh(decimal, numeric) -> BigDecimal
447+
#
448+
# Computes the inverse hyperbolic cosine of +decimal+ to the specified number of digits of
449+
# precision, +numeric+.
450+
#
451+
# If +decimal+ is NaN, returns NaN.
452+
#
453+
# BigMath.acosh(BigDecimal('2'), 16).to_s
454+
# #=> "0.1316957896924816708625046347239934461496535769096e1"
455+
#
456+
def acosh(x, prec)
457+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
458+
raise Math::DomainError, "Out of domain argument for acosh" if x < 1
459+
return BigDecimal::INFINITY if x.infinite?
460+
return BigDecimal::NAN if x.nan?
461+
462+
BigMath.log(x + sqrt(x ** 2 - 1, prec), prec)
463+
end
464+
465+
# call-seq:
466+
# atanh(decimal, numeric) -> BigDecimal
467+
#
468+
# Computes the inverse hyperbolic tangent of +decimal+ to the specified number of digits of
469+
# precision, +numeric+.
470+
#
471+
# If +decimal+ is NaN, returns NaN.
472+
#
473+
# BigMath.atanh(BigDecimal('0.5'), 16).to_s
474+
# #=> "0.549306144334054845697622618461262852323745278910789847469990412e0"
475+
#
476+
def atanh(x, prec)
477+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
478+
raise Math::DomainError, "Out of domain argument for atanh" if x < -1 || x > 1
479+
return BigDecimal::NAN if x.nan?
480+
return BigDecimal::INFINITY if x == 1
481+
return -BigDecimal::INFINITY if x == -1
482+
483+
prec += BigDecimal.double_fig
484+
prec -= x.exponent if x.exponent < 0
485+
(BigMath.log(x + 1, prec) - BigMath.log(1 - x, prec)) / 2
486+
end
487+
424488
# call-seq:
425489
# PI(numeric) -> BigDecimal
426490
#

test/bigdecimal/test_bigmath.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,52 @@ def test_hyperbolic
218218
end
219219
end
220220

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

0 commit comments

Comments
 (0)