Skip to content

Commit 1225f0d

Browse files
committed
Implement BigMath.cbrt
1 parent f266a47 commit 1225f0d

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

lib/bigdecimal/math.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#--
66
# Contents:
77
# sqrt(x, prec)
8+
# cbrt(x, prec)
89
# hypot(x, y, prec)
910
# sin (x, prec)
1011
# cos (x, prec)
@@ -46,6 +47,34 @@ def sqrt(x, prec)
4647
x.sqrt(prec)
4748
end
4849

50+
# call-seq:
51+
# cbrt(decimal, numeric) -> BigDecimal
52+
#
53+
# Computes the cube root of +decimal+ to the specified number of digits of
54+
# precision, +numeric+.
55+
#
56+
# BigMath.cbrt(BigDecimal('2'), 16).to_s
57+
# #=> "0.125992104989487316476721060727822e1"
58+
#
59+
def cbrt(x, prec)
60+
raise ArgumentError, "Zero or negative precision for cbrt" if prec <= 0
61+
return x if x.zero? || x.infinite? || x.nan?
62+
return -cbrt(-x, prec) if x < 0
63+
64+
n_digits = x.n_significant_digits
65+
prec = [prec, n_digits].max
66+
67+
ex = x.exponent / 3
68+
x *= BigDecimal("1e#{-ex * 3}")
69+
y = BigDecimal(Math.cbrt(x.to_f))
70+
precs = [prec + BigDecimal.double_fig]
71+
precs << 2 + precs.last / 2 while precs.last > BigDecimal.double_fig
72+
precs.reverse_each do |p|
73+
y = (2 * y + x.div(y, p).div(y, p)).div(3, p)
74+
end
75+
y * BigDecimal("1e#{ex}")
76+
end
77+
4978
# call-seq:
5079
# hypot(x, y, numeric) -> BigDecimal
5180
#

test/bigdecimal/test_bigmath.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ def test_sqrt
3434
assert_relative_precision {|n| sqrt(BigDecimal("2e50"), n) }
3535
end
3636

37+
def test_cbrt
38+
assert_equal(1234, cbrt(BigDecimal(1234**3), N))
39+
assert_equal(-12345, cbrt(BigDecimal(-12345**3), N))
40+
assert_equal(123 ** 456, cbrt(BigDecimal(123 ** 456) ** 3, N))
41+
assert_equal(0, cbrt(BigDecimal("0"), N))
42+
assert_equal(0, cbrt(BigDecimal("-0"), N))
43+
assert_equal(PINF, cbrt(PINF, N))
44+
assert_equal(MINF, cbrt(MINF, N))
45+
46+
assert_in_delta(SQRT2, cbrt(SQRT2 ** 3, 100), BigDecimal("1e-100"))
47+
assert_in_delta(SQRT3, cbrt(SQRT3 ** 3, 100), BigDecimal("1e-100"))
48+
assert_equal(BigDecimal("3e50"), cbrt(BigDecimal("27e150"), N))
49+
assert_equal(BigDecimal("-4e50"), cbrt(BigDecimal("-64e150"), N))
50+
assert_in_epsilon(Math.cbrt(28e150), cbrt(BigDecimal("28e150"), N))
51+
assert_in_epsilon(Math.cbrt(27e151), cbrt(BigDecimal("27e151"), N))
52+
assert_relative_precision {|n| cbrt(BigDecimal("2"), n) }
53+
assert_relative_precision {|n| cbrt(BigDecimal("2e-50"), n) }
54+
assert_relative_precision {|n| cbrt(BigDecimal("2e50"), n) }
55+
end
56+
3757
def test_hypot
3858
assert_in_delta(SQRT2, hypot(BigDecimal("1"), BigDecimal("1"), 100), BigDecimal("1e-100"))
3959
assert_in_delta(SQRT5, hypot(SQRT2, SQRT3, 100), BigDecimal("1e-100"))

0 commit comments

Comments
 (0)