File tree Expand file tree Collapse file tree 3 files changed +39
-2
lines changed
Expand file tree Collapse file tree 3 files changed +39
-2
lines changed Original file line number Diff line number Diff line change @@ -57,6 +57,13 @@ def self.infinity_computation_result # :nodoc:
5757 BigDecimal ::INFINITY
5858 end
5959
60+ def self . underflow_computation_result # :nodoc:
61+ if BigDecimal . mode ( BigDecimal ::EXCEPTION_ALL ) . anybits? ( BigDecimal ::EXCEPTION_UNDERFLOW )
62+ raise FloatDomainError , "Computation results in 'Underflow'"
63+ end
64+ BigDecimal ( 0 )
65+ end
66+
6067 def self . nan_computation_result # :nodoc:
6168 if BigDecimal . mode ( BigDecimal ::EXCEPTION_ALL ) . anybits? ( BigDecimal ::EXCEPTION_NaN )
6269 raise FloatDomainError , "Computation results to 'NaN'"
@@ -359,7 +366,17 @@ def exp(x, prec)
359366 prec = BigDecimal ::Internal . coerce_validate_prec ( prec , :exp )
360367 x = BigDecimal ::Internal . coerce_to_bigdecimal ( x , prec , :exp )
361368 return BigDecimal ::Internal . nan_computation_result if x . nan?
362- return x . positive? ? BigDecimal ::Internal . infinity_computation_result : BigDecimal ( 0 ) if x . infinite?
369+ if x . infinite? || x . exponent >= 21 # exp(10**20) and exp(-10**20) overflows/underflows 64-bit exponent
370+ if x . positive?
371+ return BigDecimal ::Internal . infinity_computation_result
372+ elsif x . infinite?
373+ # exp(-Infinity) is +0 by definition, this is not an underflow.
374+ return BigDecimal ( 0 )
375+ else
376+ return BigDecimal ::Internal . underflow_computation_result
377+ end
378+ end
379+
363380 return BigDecimal ( 1 ) if x . zero?
364381
365382 # exp(x * 10**cnt) = exp(x)**(10**cnt)
Original file line number Diff line number Diff line change @@ -71,7 +71,7 @@ def assert_infinite_calculation(positive:)
7171 BigDecimal . mode ( BigDecimal ::EXCEPTION_INFINITY , false )
7272 positive ? assert_positive_infinite ( yield ) : assert_negative_infinite ( yield )
7373 BigDecimal . mode ( BigDecimal ::EXCEPTION_INFINITY , true )
74- assert_raise_with_message ( FloatDomainError , /Infinity/ ) { yield }
74+ assert_raise_with_message ( FloatDomainError , /infinity|overflow/i ) { yield }
7575 end
7676 end
7777
@@ -83,6 +83,15 @@ def assert_negative_infinite_calculation(&block)
8383 assert_infinite_calculation ( positive : false , &block )
8484 end
8585
86+ def assert_underflow_calculation
87+ BigDecimal . save_exception_mode do
88+ BigDecimal . mode ( BigDecimal ::EXCEPTION_UNDERFLOW , false )
89+ assert_equal ( BigDecimal ( 0 ) , yield )
90+ BigDecimal . mode ( BigDecimal ::EXCEPTION_UNDERFLOW , true )
91+ assert_raise_with_message ( FloatDomainError , /underflow/i ) { yield }
92+ end
93+ end
94+
8695 def assert_nan_calculation ( &block )
8796 BigDecimal . save_exception_mode do
8897 BigDecimal . mode ( BigDecimal ::EXCEPTION_NaN , false )
Original file line number Diff line number Diff line change @@ -2296,13 +2296,24 @@ def test_exp_with_negative
22962296 end
22972297
22982298 def test_exp_with_negative_infinite
2299+ # exp(-infinity) is exactly zero. This is not an underflow.
22992300 assert_equal ( 0 , BigMath . exp ( NEGATIVE_INFINITY , 20 ) )
23002301 end
23012302
23022303 def test_exp_with_positive_infinite
23032304 assert_positive_infinite_calculation { BigMath . exp ( BigDecimal ::INFINITY , 20 ) }
23042305 end
23052306
2307+ def test_exp_with_overflow_underflow
2308+ assert_underflow_calculation { BigMath . exp ( -1e+100 , 20 ) }
2309+ assert_underflow_calculation { BigMath . exp ( -0.9e+20 , 20 ) }
2310+ assert_positive_infinite_calculation { BigMath . exp ( 1e+100 , 20 ) }
2311+ assert_positive_infinite_calculation { BigMath . exp ( 0.9e+20 , 20 ) }
2312+ huge = BigDecimal ( "0.1e#{ EXPONENT_MAX / 100 } " )
2313+ assert_positive_infinite_calculation { BigMath . exp ( huge , 20 ) }
2314+ assert_underflow_calculation { BigMath . exp ( -huge , 20 ) }
2315+ end
2316+
23062317 def test_exp_with_nan
23072318 assert_nan_calculation { BigMath . exp ( BigDecimal ::NAN , 20 ) }
23082319 end
You can’t perform that action at this time.
0 commit comments