Skip to content

Commit 73825c8

Browse files
committed
Add a fast path for sqrt when sqrt is an exact value
1 parent c816e31 commit 73825c8

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

lib/bigdecimal.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,20 @@ def sqrt(prec)
2020
raise FloatDomainError, 'sqrt of negative value' if self < 0
2121
raise FloatDomainError, "sqrt of 'NaN'(Not a Number)" if nan?
2222

23-
prec = [prec, n_significant_digits].max
23+
ten = BigDecimal(10)
24+
n_digits = n_significant_digits
25+
prec = [prec, n_digits].max
26+
27+
if n_digits < prec / 2
28+
# Fast path for sqrt(16e100) => 4e50
29+
base = ten ** ((n_digits + 1) / 2 - exponent / 2)
30+
n = self * base * base
31+
sqrt = Integer.sqrt(n)
32+
return BigDecimal(sqrt).div(base, prec) if sqrt * sqrt == n
33+
end
34+
2435
ex = prec + BigDecimal.double_fig - exponent / 2
25-
base = BigDecimal(10) ** ex
36+
base = ten ** ex
2637
sqrt = Integer.sqrt(self * base * base)
2738
BigDecimal(sqrt).div(base, prec + BigDecimal.double_fig)
2839
end

test/bigdecimal/test_bigdecimal.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,10 @@ def test_sqrt_bigdecimal
11821182
assert_equal(0, BigDecimal("-0").sqrt(1))
11831183
assert_equal(1, BigDecimal("1").sqrt(1))
11841184
assert_positive_infinite(BigDecimal("Infinity").sqrt(1))
1185+
1186+
assert_equal(BigDecimal('11.1'), BigDecimal('123.21').sqrt(100))
1187+
assert_equal(BigDecimal('11e20'), BigDecimal('121e40').sqrt(100))
1188+
assert_in_epsilon(Math.sqrt(121e41), BigDecimal('121e41').sqrt(100))
11851189
end
11861190

11871191
def test_sqrt_5266

0 commit comments

Comments
 (0)