@@ -9,12 +9,16 @@ class TestBigDecimal < Test::Unit::TestCase
99 LIMITS = RbConfig ::LIMITS
1010 else
1111 require 'fiddle'
12+ INTPTR_MAX = ( 1 << ( Fiddle ::SIZEOF_INTPTR_T *8 - 1 ) ) - 1
13+ INTPTR_MIN = [ INTPTR_MAX + 1 ] . pack ( "L!" ) . unpack ( "l!" ) [ 0 ]
1214 LONG_MAX = ( 1 << ( Fiddle ::SIZEOF_LONG *8 - 1 ) ) - 1
1315 LONG_MIN = [ LONG_MAX + 1 ] . pack ( "L!" ) . unpack ( "l!" ) [ 0 ]
1416 LLONG_MAX = ( 1 << ( Fiddle ::SIZEOF_LONG_LONG *8 - 1 ) ) - 1
1517 LLONG_MIN = [ LLONG_MAX + 1 ] . pack ( "Q!" ) . unpack ( "q!" ) [ 0 ]
1618 ULLONG_MAX = ( 1 << Fiddle ::SIZEOF_LONG_LONG *8 ) - 1
1719 LIMITS = {
20+ "INTPTR_MAX" => INTPTR_MAX ,
21+ "INTPTR_MIN" => INTPTR_MIN ,
1822 "LLONG_MIN" => LLONG_MIN ,
1923 "ULLONG_MAX" => ULLONG_MAX ,
2024 "FIXNUM_MIN" => LONG_MIN / 2 ,
@@ -25,6 +29,9 @@ class TestBigDecimal < Test::Unit::TestCase
2529 } . freeze
2630 end
2731
32+ EXPONENT_MAX = LIMITS [ 'INTPTR_MAX' ] / BASE_FIG * BASE_FIG
33+ EXPONENT_MIN = ( LIMITS [ 'INTPTR_MIN' ] - 2 ) / BASE_FIG * BASE_FIG + BASE_FIG + 1
34+
2835 ROUNDING_MODE_MAP = [
2936 [ BigDecimal ::ROUND_UP , :up ] ,
3037 [ BigDecimal ::ROUND_DOWN , :down ] ,
@@ -80,12 +87,24 @@ def test_BigDecimal
8087 assert_raise ( ArgumentError ) { BigDecimal ( "1" , -1 ) }
8188 assert_raise_with_message ( ArgumentError , /"1__1_1"/ ) { BigDecimal ( "1__1_1" ) }
8289 assert_raise_with_message ( ArgumentError , /"_1_1_1"/ ) { BigDecimal ( "_1_1_1" ) }
90+ assert ( BigDecimal ( "0.1E#{ EXPONENT_MAX } " ) . finite? )
91+ assert ( BigDecimal ( "0.1E#{ EXPONENT_MIN } " ) . finite? )
8392
8493 BigDecimal . save_exception_mode do
8594 BigDecimal . mode ( BigDecimal ::EXCEPTION_OVERFLOW , false )
95+ BigDecimal . mode ( BigDecimal ::EXCEPTION_UNDERFLOW , false )
8696 BigDecimal . mode ( BigDecimal ::EXCEPTION_NaN , false )
8797 assert_positive_infinite ( BigDecimal ( "Infinity" ) )
88- assert_positive_infinite ( BigDecimal ( "1E1111111111111111111" ) )
98+ assert_positive_infinite ( BigDecimal ( "0.1E#{ EXPONENT_MAX + 1 } " ) )
99+ assert_negative_infinite ( BigDecimal ( "-0.1E#{ EXPONENT_MAX + 1 } " ) )
100+ assert_positive_infinite ( BigDecimal ( "1E#{ EXPONENT_MAX } " ) )
101+ assert_negative_infinite ( BigDecimal ( "-1E#{ EXPONENT_MAX } " ) )
102+ assert_positive_zero ( BigDecimal ( "0E#{ EXPONENT_MAX + 1 } " ) )
103+ assert_negative_zero ( BigDecimal ( "-0E#{ EXPONENT_MAX + 1 } " ) )
104+ assert_positive_zero ( BigDecimal ( "0.1E#{ EXPONENT_MIN - 1 } " ) )
105+ assert_negative_zero ( BigDecimal ( "-0.1E#{ EXPONENT_MIN - 1 } " ) )
106+ assert_positive_zero ( BigDecimal ( "0.01E#{ EXPONENT_MIN } " ) )
107+ assert_negative_zero ( BigDecimal ( "-0.01E#{ EXPONENT_MIN } " ) )
89108 assert_positive_infinite ( BigDecimal ( " \t \n \r \r Infinity \t \n \r \r " ) )
90109 assert_negative_infinite ( BigDecimal ( "-Infinity" ) )
91110 assert_negative_infinite ( BigDecimal ( " \t \n \r \r -Infinity \t \n \r \r " ) )
@@ -460,39 +479,48 @@ def test_exception_overflow
460479 end
461480 end
462481
482+ def test_add_sub_underflow
483+ BigDecimal . mode ( BigDecimal ::EXCEPTION_UNDERFLOW , false )
484+ x = BigDecimal ( "0.100000000002E#{ EXPONENT_MIN + 10 } " )
485+ y = BigDecimal ( "0.100000000001E#{ EXPONENT_MIN + 10 } " )
486+ z = BigDecimal ( "0.101E#{ EXPONENT_MIN + 10 } " )
487+ assert_not_equal ( 0 , x - z )
488+ assert_not_equal ( 0 , z - y )
489+ assert_positive_zero ( x + ( -y ) )
490+ assert_positive_zero ( x - y )
491+ assert_positive_zero ( ( -y ) - ( -x ) )
492+ assert_negative_zero ( ( -x ) + y )
493+ assert_negative_zero ( y - x )
494+ assert_negative_zero ( ( -x ) - ( -y ) )
495+ end
496+
463497 def test_mult_div_overflow_underflow_sign
464498 BigDecimal . mode ( BigDecimal ::EXCEPTION_OVERFLOW , false )
465499 BigDecimal . mode ( BigDecimal ::EXCEPTION_UNDERFLOW , false )
500+ large_x = BigDecimal ( "0.1E#{ EXPONENT_MAX } " )
501+ small_x = BigDecimal ( "0.1E#{ EXPONENT_MIN } " )
466502
467- large_x = BigDecimal ( "10" )
468- 100 . times do
469- x2 = large_x * large_x
470- break if x2 . infinite?
471- large_x = x2
472- end
473-
474- small_x = BigDecimal ( "0.1" )
475- 100 . times do
476- x2 = small_x * small_x
477- break if x2 . zero?
478- small_x = x2
479- end
480-
503+ assert_positive_infinite ( large_x * 10 )
504+ assert_positive_infinite ( 10 * large_x )
481505 assert_positive_infinite ( large_x * large_x )
482506 assert_negative_infinite ( large_x * ( -large_x ) )
483507 assert_negative_infinite ( ( -large_x ) * large_x )
484508 assert_positive_infinite ( ( -large_x ) * ( -large_x ) )
485509
510+ assert_positive_zero ( small_x * 0.1 )
511+ assert_positive_zero ( 0.1 * small_x )
486512 assert_positive_zero ( small_x * small_x )
487513 assert_negative_zero ( small_x * ( -small_x ) )
488514 assert_negative_zero ( ( -small_x ) * small_x )
489515 assert_positive_zero ( ( -small_x ) * ( -small_x ) )
490516
517+ assert_positive_infinite ( large_x . div ( 0.1 , 10 ) )
491518 assert_positive_infinite ( large_x . div ( small_x , 10 ) )
492519 assert_negative_infinite ( large_x . div ( -small_x , 10 ) )
493520 assert_negative_infinite ( ( -large_x ) . div ( small_x , 10 ) )
494521 assert_positive_infinite ( ( -large_x ) . div ( -small_x , 10 ) )
495522
523+ assert_positive_zero ( small_x . div ( 10 , 10 ) )
496524 assert_positive_zero ( small_x . div ( large_x , 10 ) )
497525 assert_negative_zero ( small_x . div ( -large_x , 10 ) )
498526 assert_negative_zero ( ( -small_x ) . div ( large_x , 10 ) )
@@ -1567,9 +1595,9 @@ def test_inspect
15671595 assert_equal ( "0.123456789012e0" , BigDecimal ( "0.123456789012" ) . inspect )
15681596 assert_equal ( "0.123456789012e4" , BigDecimal ( "1234.56789012" ) . inspect )
15691597 assert_equal ( "0.123456789012e-4" , BigDecimal ( "0.0000123456789012" ) . inspect )
1570- s = '-0.123456789e-1000000000000000008'
1571- x = BigDecimal ( s )
1572- assert_equal ( s , x . inspect ) unless x . infinite?
1598+ # Frac part is fully packed, exponent is minimum multiple of BASE_FIG
1599+ s = "-0. #{ '1' * BASE_FIG } e #{ ( EXPONENT_MIN / BASE_FIG + 1 ) * BASE_FIG } "
1600+ assert_equal ( s , BigDecimal ( s ) . inspect )
15731601 end
15741602
15751603 def test_power
0 commit comments