Skip to content

Commit 062f7ad

Browse files
committed
Implement hyperbolic functions(sinh, cosh, tanh)
1 parent 697e487 commit 062f7ad

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
# acos(x, prec)
1515
# atan(x, prec)
1616
# atan2(y, x, prec)
17+
# sinh (x, prec)
18+
# cosh (x, prec)
19+
# tanh (x, prec)
1720
# PI (prec)
1821
# E (prec) == exp(1.0,prec)
1922
#
@@ -336,6 +339,72 @@ def atan2(y, x, prec)
336339
neg ? -v : v
337340
end
338341

342+
# call-seq:
343+
# sinh(decimal, numeric) -> BigDecimal
344+
#
345+
# Computes the hyperbolic sine of +decimal+ to the specified number of digits of
346+
# precision, +numeric+.
347+
#
348+
# If +decimal+ is NaN, returns NaN.
349+
#
350+
# BigMath.sinh(BigDecimal('1'), 16).to_s
351+
# #=> "0.11752011936438014568823818505956e1"
352+
#
353+
def sinh(x, prec)
354+
raise ArgumentError, "Zero or negative precision for sinh" if prec <= 0
355+
return BigDecimal::NAN if x.nan?
356+
return x if x.infinite?
357+
358+
prec += BigDecimal.double_fig
359+
prec -= x.exponent if x.exponent < 0
360+
e = BigMath.exp(x, prec)
361+
(e - BigDecimal(1).div(e, prec)).div(2, prec)
362+
end
363+
364+
# call-seq:
365+
# cosh(decimal, numeric) -> BigDecimal
366+
#
367+
# Computes the hyperbolic cosine of +decimal+ to the specified number of digits of
368+
# precision, +numeric+.
369+
#
370+
# If +decimal+ is NaN, returns NaN.
371+
#
372+
# BigMath.cosh(BigDecimal('1'), 16).to_s
373+
# #=> "0.15430806348152437784779056207571e1"
374+
#
375+
def cosh(x, prec)
376+
raise ArgumentError, "Zero or negative precision for cosh" if prec <= 0
377+
return BigDecimal::NAN if x.nan?
378+
return BigDecimal::INFINITY if x.infinite?
379+
380+
prec += BigDecimal.double_fig
381+
e = BigMath.exp(x, prec)
382+
(e + BigDecimal(1).div(e, prec)).div(2, prec)
383+
end
384+
385+
# call-seq:
386+
# tanh(decimal, numeric) -> BigDecimal
387+
#
388+
# Computes the hyperbolic tangent of +decimal+ to the specified number of digits of
389+
# precision, +numeric+.
390+
#
391+
# If +decimal+ is NaN, returns NaN.
392+
#
393+
# BigMath.tanh(BigDecimal('1'), 16).to_s
394+
# #=> "0.7615941559557648881194582826048e0"
395+
#
396+
def tanh(x, prec)
397+
raise ArgumentError, "Zero or negative precision for tanh" if prec <= 0
398+
return BigDecimal::NAN if x.nan?
399+
return BigDecimal(x.infinite?) if x.infinite?
400+
401+
prec += BigDecimal.double_fig
402+
prec2 = prec + [-x.exponent, 0].max
403+
e = BigMath.exp(x, prec2)
404+
einv = BigDecimal(1).div(e, prec2)
405+
(e - einv).div(e + einv, prec)
406+
end
407+
339408
# call-seq:
340409
# PI(numeric) -> BigDecimal
341410
#

test/bigdecimal/test_bigmath.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,33 @@ def test_atan2
199199
end
200200
end
201201

202+
def test_hyperbolic
203+
[-1, 0, 0.5, 1, 10].each do |x|
204+
assert_in_delta(Math.sinh(x), sinh(BigDecimal(x.to_s), N))
205+
assert_in_delta(Math.cosh(x), cosh(BigDecimal(x.to_s), N))
206+
assert_in_delta(Math.tanh(x), tanh(BigDecimal(x.to_s), N))
207+
end
208+
[MINF, BigDecimal(0), PINF].each do |x|
209+
assert_equal(Math.sinh(x.to_f), sinh(x, N).to_f)
210+
assert_equal(Math.cosh(x.to_f), cosh(x, N).to_f)
211+
assert_equal(Math.tanh(x.to_f), tanh(x, N).to_f)
212+
end
213+
214+
x = BigDecimal("0.3")
215+
assert_in_delta(tanh(x, 100), sinh(x, 100) / cosh(x, 100), BigDecimal("1e-100"))
216+
217+
e = E(116)
218+
assert_in_delta((e - 1 / e) / 2, sinh(BigDecimal(1), 100), BigDecimal("1e-100"))
219+
assert_in_delta((e + 1 / e) / 2, cosh(BigDecimal(1), 100), BigDecimal("1e-100"))
220+
assert_in_delta((e - 1 / e) / (e + 1 / e), tanh(BigDecimal(1), 100), BigDecimal("1e-100"))
221+
222+
["1e-30", "0.2", "10", "100"].each do |x|
223+
assert_relative_precision {|n| sinh(BigDecimal(x), n)}
224+
assert_relative_precision {|n| cosh(BigDecimal(x), n)}
225+
assert_relative_precision {|n| tanh(BigDecimal(x), n)}
226+
end
227+
end
228+
202229
def test_exp
203230
[-100, -2, 0.5, 10, 100].each do |x|
204231
assert_in_epsilon(Math.exp(x), BigMath.exp(BigDecimal(x, 0), N))

0 commit comments

Comments
 (0)