diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | ext/bigdecimal/bigdecimal.c | 6 | ||||
-rw-r--r-- | test/bigdecimal/test_bigdecimal.rb | 32 |
3 files changed, 36 insertions, 8 deletions
@@ -1,3 +1,9 @@ +Thu Aug 30 16:17:52 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * ext/bigdecimal/bigdecimal.c (BigDecimal_to_f): check underflow since + strtod() sets errno to ERANGE at underflow too. [ruby-core:47342] + [Bug #6944] + Thu Aug 30 12:44:43 2012 Akinori MUSHA <knu@iDaemons.org> * lib/set.rb (Set#{<,>,<=,>=}): Define comparison operators as diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 866ce345fc..e8ba40a531 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -696,8 +696,10 @@ BigDecimal_to_f(VALUE self) VpToString(p, buf, 0, 0); errno = 0; d = strtod(buf, 0); - if (errno == ERANGE) - goto overflow; + if (errno == ERANGE) { + if (d == 0.0) goto underflow; + if (fabs(d) >= HUGE_VAL) goto overflow; + } return rb_float_new(d); overflow: diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index d440e4cedb..6694697e0e 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -540,15 +540,35 @@ class TestBigDecimal < Test::Unit::TestCase assert_kind_of(Float, x .to_f) assert_kind_of(Float, (-x).to_f) + bug6944 = '[ruby-core:47342]' + BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, true) - assert_raise(FloatDomainError) { - BigDecimal("1e#{Float::MIN_10_EXP - 2*Float::DIG}").to_f } - assert_raise(FloatDomainError) { - BigDecimal("-1e#{Float::MIN_10_EXP - 2*Float::DIG}").to_f } + x = "1e#{Float::MIN_10_EXP - 2*Float::DIG}" + assert_raise(FloatDomainError, x) {BigDecimal(x).to_f} + x = "-#{x}" + assert_raise(FloatDomainError, x) {BigDecimal(x).to_f} + x = "1e#{Float::MIN_10_EXP - Float::DIG}" + assert_nothing_raised(FloatDomainError, x) { + assert_in_delta(0.0, BigDecimal(x).to_f, 10**Float::MIN_10_EXP, bug6944) + } + x = "-#{x}" + assert_nothing_raised(FloatDomainError, x) { + assert_in_delta(0.0, BigDecimal(x).to_f, 10**Float::MIN_10_EXP, bug6944) + } BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, false) - assert_equal( 0.0, BigDecimal("1e#{Float::MIN_10_EXP - 2*Float::DIG}").to_f) - assert_equal(-0.0, BigDecimal("-1e#{Float::MIN_10_EXP - 2*Float::DIG}").to_f) + x = "1e#{Float::MIN_10_EXP - 2*Float::DIG}" + assert_equal( 0.0, BigDecimal(x).to_f, x) + x = "-#{x}" + assert_equal(-0.0, BigDecimal(x).to_f, x) + x = "1e#{Float::MIN_10_EXP - Float::DIG}" + assert_nothing_raised(FloatDomainError, x) { + assert_in_delta(0.0, BigDecimal(x).to_f, 10**Float::MIN_10_EXP, bug6944) + } + x = "-#{x}" + assert_nothing_raised(FloatDomainError, x) { + assert_in_delta(0.0, BigDecimal(x).to_f, 10**Float::MIN_10_EXP, bug6944) + } end def test_coerce |