diff --git a/ChangeLog b/ChangeLog index 4a9d1ab7fb..6c16c22e66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Sat Oct 30 17:23:19 2010 Nobuyoshi Nakada + + * util.c (ruby_strtod): get rid of overflow/underflow as possible. + Sat Oct 30 14:37:39 2010 Nobuyoshi Nakada * configure.in (ruby_pc): erase runtime-defined variables and diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index dd61f1919b..7ab4ffc649 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -102,7 +102,14 @@ class TestFloat < Test::Unit::TestCase assert_equal(0.0009765625, Float("0x1p-10")) assert_equal(2.6881171418161356e+43, Float("0x1.3494a9b171bf5p+144")) assert_equal(-3.720075976020836e-44, Float("-0x1.a8c1f14e2af5dp-145")) - + assert_equal(31.0*2**1019, Float("0x0."+("0"*268)+"1fp2099")) + assert_equal(31.0*2**1019, Float("0x0."+("0"*600)+"1fp3427")) + assert_equal(-31.0*2**1019, Float("-0x0."+("0"*268)+"1fp2099")) + assert_equal(-31.0*2**1019, Float("-0x0."+("0"*600)+"1fp3427")) + assert_equal(31.0*2**-1027, Float("0x1f"+("0"*268)+".0p-2099")) + assert_equal(31.0*2**-1027, Float("0x1f"+("0"*600)+".0p-3427")) + assert_equal(-31.0*2**-1027, Float("-0x1f"+("0"*268)+".0p-2099")) + assert_equal(-31.0*2**-1027, Float("-0x1f"+("0"*600)+".0p-3427")) end def test_divmod diff --git a/util.c b/util.c index 19602420b5..99b8a3fd9b 100644 --- a/util.c +++ b/util.c @@ -2122,21 +2122,38 @@ break2: static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; s0 = ++s; adj = 0; - aadj = -1; + aadj = 1.0; + nd0 = -4; if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; - do { - adj *= 16; - adj += (s1 - hexdigit) & 15; - } while (*++s && (s1 = strchr(hexdigit, *s))); + while (*s == '0') s++; + if ((s1 = strchr(hexdigit, *s)) != NULL) { + do { + adj += aadj * ((s1 - hexdigit) & 15); + nd0 += 4; + aadj /= 16; + } while (*++s && (s1 = strchr(hexdigit, *s))); + } if (*s == '.') { - aadj = 1.; + dsign = 1; if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; - do { - aadj /= 16; + if (nd0 < 0) { + while (*s == '0') { + s++; + nd0 -= 4; + } + } + for (; *s && (s1 = strchr(hexdigit, *s)); ++s) { adj += aadj * ((s1 - hexdigit) & 15); - } while (*++s && (s1 = strchr(hexdigit, *s))); + if ((aadj /= 16) == 0.0) { + while (strchr(hexdigit, *++s)); + break; + } + } + } + else { + dsign = 0; } if (*s == 'P' || *s == 'p') { @@ -2153,17 +2170,16 @@ break2: nd -= '0'; c = *++s; /* Float("0x0."+("0"*267)+"1fp2095") */ - if (abs(nd) > 2095) { + if (nd + dsign * nd0 > 2095) { while ('0' <= c && c <= '9') c = *++s; break; } } while ('0' <= c && c <= '9'); - dval(rv) = ldexp(adj, nd * dsign); } else { - if (aadj != -1) goto ret0; - dval(rv) = adj; + if (dsign) goto ret0; } + dval(rv) = ldexp(adj, nd * dsign + nd0); goto ret; } nz0 = 1;