Skip to content

Commit d785685

Browse files
committed
Coerce rational with the given prec in exp, log and power calculation
1 parent ec2748a commit d785685

2 files changed

Lines changed: 22 additions & 6 deletions

File tree

lib/bigdecimal.rb

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def **(y)
4444
def power(y, prec = nil)
4545
BigMath._validate_prec(prec, :power) if prec
4646
x = self
47-
y = BigMath._coerce_to_bigdecimal(y, :power)
47+
y = BigMath._coerce_to_bigdecimal(y, prec || 0, :power)
4848

4949
return BigMath._nan_computation_result if x.nan? || y.nan?
5050
return BigDecimal(1) if y.zero?
@@ -145,12 +145,17 @@ def power(y, prec = nil)
145145
# Core BigMath methods for BigDecimal (log, exp) are defined here.
146146
# Other methods (sin, cos, atan) are defined in 'bigdecimal/math.rb'.
147147
module BigMath
148-
def self._coerce_to_bigdecimal(x, method_name, complex_domain_error = false) # :nodoc:
148+
149+
# Coerce x to BigDecimal with the specified precision.
150+
# TODO: some methods (example: BigMath.exp) require more precision than specified to coerce.
151+
def self._coerce_to_bigdecimal(x, prec, method_name, complex_domain_error = false) # :nodoc:
149152
case x
150153
when BigDecimal
151154
return x
152-
when Integer, Float, Rational
153-
return BigDecimal(x, 0)
155+
when Integer, Float
156+
return BigDecimal(x)
157+
when Rational
158+
return BigDecimal(x, [prec, 2 * BigDecimal.double_fig].max)
154159
when Complex
155160
if complex_domain_error
156161
raise Math::DomainError, "Complex argument for BigMath.#{method_name}"
@@ -192,7 +197,7 @@ def self._nan_computation_result # :nodoc:
192197
#
193198
def self.log(x, prec)
194199
_validate_prec(prec, :log)
195-
x = _coerce_to_bigdecimal(x, :log, true)
200+
x = _coerce_to_bigdecimal(x, prec, :log, true)
196201
return _nan_computation_result if x.nan?
197202
raise Math::DomainError, 'Zero or negative argument for log' if x <= 0
198203
return _infinity_computation_result if x.infinite?
@@ -258,7 +263,7 @@ def self.log(x, prec)
258263
#
259264
def self.exp(x, prec)
260265
_validate_prec(prec, :exp)
261-
x = _coerce_to_bigdecimal(x, :exp)
266+
x = _coerce_to_bigdecimal(x, prec, :exp)
262267
return _nan_computation_result if x.nan?
263268
return x.positive? ? _infinity_computation_result : BigDecimal(0) if x.infinite?
264269
return BigDecimal(1) if x.zero?

test/bigdecimal/test_bigdecimal.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,12 @@ def test_power_with_prec
18951895
assert_equal(BigDecimal('0.5394221232e-7'), BigDecimal('0.12345').power(8, 10))
18961896
end
18971897

1898+
def test_power_with_rational
1899+
x = BigDecimal(2)
1900+
assert_in_epsilon(x.power(BigDecimal(3 / 7r, 100), 100), x.power(3 / 7r, 100), 1e-90)
1901+
assert_in_epsilon(x.power(BigDecimal(3 / 7r, 100), 100), x.power(3 / 7r), 1e-15)
1902+
end
1903+
18981904
def test_power_precision
18991905
x = BigDecimal("1.41421356237309504880168872420969807856967187537695")
19001906
y = BigDecimal("3.14159265358979323846264338327950288419716939937511")
@@ -2153,6 +2159,7 @@ def test_BigMath_exp_with_rational
21532159
assert_in_epsilon(Math.exp(40), BigMath.exp(Rational(80,2), prec))
21542160
assert_in_epsilon(Math.exp(-20), BigMath.exp(Rational(-40,2), prec))
21552161
assert_in_epsilon(Math.exp(-40), BigMath.exp(Rational(-80,2), prec))
2162+
assert_in_epsilon(BigMath.exp(BigDecimal(3 / 7r, 100), 100), BigMath.exp(3 / 7r, 100), 1e-90)
21562163
end
21572164

21582165
def test_BigMath_exp_under_gc_stress
@@ -2285,6 +2292,10 @@ def test_BigMath_log_with_reciprocal_of_42
22852292
assert_in_delta(Math.log(1e-42), BigMath.log(BigDecimal("1e-42"), 20))
22862293
end
22872294

2295+
def test_BigMath_log_with_rational
2296+
assert_in_epsilon(BigMath.log(BigDecimal(3 / 7r, 100), 100), BigMath.log(3 / 7r, 100), 1e-90)
2297+
end
2298+
22882299
def test_BigMath_log_under_gc_stress
22892300
paths = $LOAD_PATH.map{|path| "-I#{path}" }
22902301
assert_in_out_err([*paths, "-rbigdecimal", "--disable-gems"], <<-EOS, [], [])

0 commit comments

Comments
 (0)