@@ -46,29 +46,36 @@ def power(y, prec = nil)
4646 x = self
4747 y = BigMath . _coerce_to_bigdecimal ( y , :power )
4848
49- return BigDecimal ::NAN if x . nan? || y . nan?
49+ return BigMath . _nan_computation_result if x . nan? || y . nan?
50+ return BigDecimal ( 1 ) if y . zero?
5051
5152 if y . infinite?
5253 if x < 0
5354 return BigDecimal ( 0 ) if x < -1 && y . negative?
5455 return BigDecimal ( 0 ) if x > -1 && y . positive?
5556 raise Math ::DomainError , 'Result undefined for negative base raised to infinite power'
5657 elsif x < 1
57- return y . positive? ? BigDecimal ( 0 ) : BigDecimal :: INFINITY
58+ return y . positive? ? BigDecimal ( 0 ) : BigMath . _infinity_computation_result
5859 elsif x == 1
5960 return BigDecimal ( 1 )
6061 else
61- return y . positive? ? BigDecimal :: INFINITY : BigDecimal ( 0 )
62+ return y . positive? ? BigMath . _infinity_computation_result : BigDecimal ( 0 )
6263 end
6364 end
6465
66+ if x . infinite? && y < 0
67+ # Computation result will be +0 or -0. Avoid overflow.
68+ neg = x < 0 && y . frac . zero? && y % 2 == 1
69+ return neg ? -BigDecimal ( 0 ) : BigDecimal ( 0 )
70+ end
71+
6572 if x . zero?
6673 return BigDecimal ( 1 ) if y . zero?
6774 return BigDecimal ( 0 ) if y > 0
6875 if y . frac . zero? && y % 2 == 1 && x . sign == -1
69- return -BigDecimal :: INFINITY
76+ return -BigMath . _infinity_computation_result
7077 else
71- return BigDecimal :: INFINITY
78+ return BigMath . _infinity_computation_result
7279 end
7380 elsif x < 0
7481 if y . frac . zero?
@@ -101,7 +108,7 @@ def power(y, prec = nil)
101108 xn *= xn
102109 # Detect overflow/underflow before consuming infinite memory
103110 if ( xn . exponent . abs - 1 ) * int_part / n >= 0x7FFFFFFFFFFFFFFF
104- return ( ( xn . exponent > 0 ) ^ neg ? BigDecimal :: INFINITY : BigDecimal ( 0 ) ) * ( int_part . even? || x > 0 ? 1 : -1 )
111+ return ( ( xn . exponent > 0 ) ^ neg ? BigMath . _infinity_computation_result : BigDecimal ( 0 ) ) * ( int_part . even? || x > 0 ? 1 : -1 )
105112 end
106113 end
107114 return neg ? BigDecimal ( 1 ) / ans : ans
@@ -112,7 +119,7 @@ def power(y, prec = nil)
112119 if y < 0
113120 inv = x . power ( -y , prec )
114121 return BigDecimal ( 0 ) if inv . infinite?
115- return BigDecimal :: INFINITY if inv . zero?
122+ return BigMath . _infinity_computation_result if inv . zero?
116123 return BigDecimal ( 1 ) . div ( inv , prec )
117124 end
118125
@@ -138,7 +145,7 @@ def power(y, prec = nil)
138145# Core BigMath methods for BigDecimal (log, exp) are defined here.
139146# Other methods (sin, cos, atan) are defined in 'bigdecimal/math.rb'.
140147module BigMath
141- def self . _coerce_to_bigdecimal ( x , method_name , complex_domain_error = false )
148+ def self . _coerce_to_bigdecimal ( x , method_name , complex_domain_error = false ) # :nodoc:
142149 case x
143150 when BigDecimal
144151 return x
@@ -152,11 +159,25 @@ def self._coerce_to_bigdecimal(x, method_name, complex_domain_error = false)
152159 raise ArgumentError , "#{ x . inspect } can't be coerced into BigDecimal"
153160 end
154161
155- def self . _validate_prec ( prec , method_name )
162+ def self . _validate_prec ( prec , method_name ) # :nodoc:
156163 raise ArgumentError , 'precision must be an Integer' unless Integer === prec
157164 raise ArgumentError , "Zero or negative precision for #{ method_name } " if prec <= 0
158165 end
159166
167+ def self . _infinity_computation_result # :nodoc:
168+ if BigDecimal . mode ( BigDecimal ::EXCEPTION_ALL ) . anybits? ( BigDecimal ::EXCEPTION_INFINITY )
169+ raise FloatDomainError , "Computation results in 'Infinity'"
170+ end
171+ BigDecimal ::INFINITY
172+ end
173+
174+ def self . _nan_computation_result # :nodoc:
175+ if BigDecimal . mode ( BigDecimal ::EXCEPTION_ALL ) . anybits? ( BigDecimal ::EXCEPTION_NaN )
176+ raise FloatDomainError , "Computation results to 'NaN'"
177+ end
178+ BigDecimal ::NAN
179+ end
180+
160181 # call-seq:
161182 # BigMath.log(decimal, numeric) -> BigDecimal
162183 #
@@ -172,9 +193,9 @@ def self._validate_prec(prec, method_name)
172193 def self . log ( x , prec )
173194 _validate_prec ( prec , :log )
174195 x = _coerce_to_bigdecimal ( x , :log , true )
175- return BigDecimal :: NAN if x . nan?
196+ return _nan_computation_result if x . nan?
176197 raise Math ::DomainError , 'Zero or negative argument for log' if x <= 0
177- return BigDecimal :: INFINITY if x . infinite?
198+ return _infinity_computation_result if x . infinite?
178199 return BigDecimal ( 0 ) if x == 1
179200
180201 if x > 10 || x < 0.1
@@ -238,8 +259,8 @@ def self.log(x, prec)
238259 def self . exp ( x , prec )
239260 _validate_prec ( prec , :exp )
240261 x = _coerce_to_bigdecimal ( x , :exp )
241- return BigDecimal :: NAN if x . nan?
242- return x . positive? ? BigDecimal :: INFINITY : BigDecimal ( 0 ) if x . infinite?
262+ return _nan_computation_result if x . nan?
263+ return x . positive? ? _infinity_computation_result : BigDecimal ( 0 ) if x . infinite?
243264 return BigDecimal ( 1 ) if x . zero?
244265 return BigDecimal ( 1 ) . div ( exp ( -x , prec ) , prec ) if x < 0
245266
0 commit comments