山本です。 util.c(ruby_strtod) にバグがありました _no E:\ruby-cvs>ruby -ve "p Float('.')" ruby 1.8.1 (2003-12-25) [i386-bccwin32] -e:1:in `Float': invalid value for Float(): "." (ArgumentError) from -e:1 E:\ruby-cvs\ruby_1_8>miniruby -ve "p Float('.')" ruby 1.8.2 (2004-07-09) [i386-bccwin32] 0.0 というように、数字が全くない場合にも 0.0 となっていました。 0.0000000000001 で preceding 0 を mantissa に数えないように変更したとき、 入ったバグです。 コメントでは "-I.FE-X" で Either I or F may be omitted, or both. とあるのですが、ruby1.8.1, mingw32, bcc32 のいずれも両方省略すると 変換しないので、やはりバグだと思います。 下のテストと一緒に、明日の正午コミットしようと思います。問題があれば、 ご指摘お願いします。 Index: util.c =================================================================== RCS file: /var/cvs/src/ruby/util.c,v retrieving revision 1.43 diff -u -w -b -p -r1.43 util.c --- util.c 14 May 2004 03:17:29 -0000 1.43 +++ util.c 13 Jul 2004 09:51:58 -0000 @@ -722,7 +722,8 @@ ruby_strtod(string, endPtr) * fractional part of the mantissa, and X * is the exponent. Either of the signs * may be "+", "-", or omitted. Either I - * or F may be omitted, or both. The decimal + * or F may be omitted, but cannot be ommitted + * at once. The decimal * point isn't necessary unless F is present. * The "E" may actually be an "e". E and X * may both be omitted (but not just one). @@ -745,7 +746,8 @@ ruby_strtod(string, endPtr) * case, fracExp is incremented one for each * dropped digit. */ int mantSize = 0; /* Number of digits in mantissa. */ - int decPt = FALSE; /* mantissa has decimal point. */ + int hasPoint = FALSE; /* Decimal point exists. */ + int hasDigit = FALSE; /* I or F exists. */ const char *pMant; /* Temporarily holds location of mantissa * in string. */ const char *pExp; /* Temporarily holds location of exponent @@ -778,13 +780,13 @@ ruby_strtod(string, endPtr) for ( ; c = *p; p += 1) { if (!ISDIGIT(c)) { - if (c != '.' || decPt) { + if (c != '.' || hasPoint) { break; } - decPt = TRUE; + hasPoint = TRUE; } else { - if (decPt) { /* already in fractional part */ + if (hasPoint) { /* already in fractional part */ fracExp -= 1; } if (mantSize) { /* already in mantissa */ @@ -794,6 +796,7 @@ ruby_strtod(string, endPtr) mantSize += 1; pMant = p; } + hasDigit = TRUE; } } @@ -812,7 +815,11 @@ ruby_strtod(string, endPtr) fracExp += (mantSize - 18); mantSize = 18; } - { + if (!hasDigit) { + fraction = 0.0; + p = string; + } + else { int frac1, frac2; frac1 = 0; for ( ; mantSize > 9; mantSize -= 1) { Index: test_float.rb =================================================================== RCS file: /var/cvs/src/ruby/test/ruby/test_float.rb,v retrieving revision 1.10 diff -u -w -b -p -r1.10 test_float.rb --- test_float.rb 15 May 2004 08:54:23 -0000 1.10 +++ test_float.rb 13 Jul 2004 09:57:21 -0000 @@ -61,6 +61,23 @@ class TestFloat < Test::Unit::TestCase assert(a.abs < Float::EPSILON) a = Float("-0.0") assert(a.abs < Float::EPSILON) + a = Float(".0") + assert(a.abs < Float::EPSILON) + a = Float("+.0") + assert(a.abs < Float::EPSILON) + a = Float("-.0") + assert(a.abs < Float::EPSILON) + a = Float("0.") + assert(a.abs < Float::EPSILON) + a = Float("+0.") + assert(a.abs < Float::EPSILON) + a = Float("-0.") + assert(a.abs < Float::EPSILON) + assert_raise(ArgumentError){Float(".")} + assert_raise(ArgumentError){Float("+")} + assert_raise(ArgumentError){Float("+.")} + assert_raise(ArgumentError){Float("-")} + assert_raise(ArgumentError){Float("-.")} a = Float("0." + "00" * Float::DIG + "1") assert(a != 0.0) a = Float("+0." + "00" * Float::DIG + "1")