From: Yukihiro Matsumoto Date: 2006-04-28T10:59:29+09:00 Subject: Re: [ ruby-Bugs-4284 ] Float near Float::MIN Hi, In message "Re: [ ruby-Bugs-4284 ] Float near Float::MIN" on Fri, 28 Apr 2006 04:14:47 +0900, noreply@rubyforge.org writes: |3. comment: |since 2.2250738585072e-308 is a legitimate Floating point number, and meant to be the smallest above zero, I would expect 1e-307, which is more than that to be working correctly. But I get: |- a weird warning which should not occur |- a wrong output which is off about by a factor of 10**16 |- a output which should not be a legitimate Float, because it is between 0 and Float::MIN The built-in strtod() function cut off exponent digits too early. This is a patch to fix this. matz. --- util.c 17 Feb 2006 02:21:35 -0000 1.50 +++ util.c 28 Apr 2006 01:56:38 -0000 @@ -17,2 +17,3 @@ #include +#include @@ -666,18 +667,4 @@ ruby_getcwd(void) -#define TRUE 1 -#define FALSE 0 - static int MDMINEXPT = -323; -static int MDMAXEXPT = 309; -static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ - 10.0, /* is 10^2^i. Used to convert decimal */ - 100.0, /* exponents into floating-point numbers. */ - 1.0e4, - 1.0e8, - 1.0e16, - 1.0e32, - 1.0e64, - 1.0e128, - 1.0e256 -}; +static int MDMAXEXPT = 309; @@ -722,4 +709,4 @@ ruby_strtod( { - int sign, expSign = FALSE; - double fraction, dblExp, *d; + int sign, expSign = Qfalse; + double fraction = 0.0, dblExp; register const char *p; @@ -737,4 +724,4 @@ ruby_strtod( int mantSize = 0; /* Number of digits in mantissa. */ - int hasPoint = FALSE; /* Decimal point exists. */ - int hasDigit = FALSE; /* I or F exists. */ + int hasPoint = Qfalse; /* Decimal point exists. */ + int hasDigit = Qfalse; /* I or F exists. */ const char *pMant; /* Temporarily holds location of mantissa @@ -754,3 +741,3 @@ ruby_strtod( if (*p == '-') { - sign = TRUE; + sign = Qtrue; p += 1; @@ -761,3 +748,3 @@ ruby_strtod( } - sign = FALSE; + sign = Qfalse; } @@ -774,3 +761,3 @@ ruby_strtod( } - hasPoint = TRUE; + hasPoint = Qtrue; } @@ -787,3 +774,3 @@ ruby_strtod( } - hasDigit = TRUE; + hasDigit = Qtrue; } @@ -811,3 +798,3 @@ ruby_strtod( else { - int frac1, frac2; + double frac1, frac2; frac1 = 0; @@ -841,3 +828,3 @@ ruby_strtod( if (*p == '-') { - expSign = TRUE; + expSign = Qtrue; p += 1; @@ -848,3 +835,3 @@ ruby_strtod( } - expSign = FALSE; + expSign = Qfalse; } @@ -875,34 +862,35 @@ ruby_strtod( - if (exp >= MDMAXEXPT - 18) { - exp = MDMAXEXPT; + if (exp >= MDMAXEXPT) { errno = ERANGE; + return HUGE_VAL * (sign ? -1.0 : 1.0); } - else if (exp < MDMINEXPT + 18) { - exp = MDMINEXPT; + else if (exp < MDMINEXPT) { errno = ERANGE; + return 0.0 * (sign ? -1.0 : 1.0); } - fracExp = exp; - exp += 9; - if (exp < 0) { - expSign = TRUE; - exp = -exp; - } - else { - expSign = FALSE; - } - dblExp = 1.0; - for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { - if (exp & 01) { - dblExp *= *d; + if (frac1 > 0) { + fracExp = exp; + exp += 9; + if (exp < 0) { + expSign = Qtrue; + exp = -exp; } + else { + expSign = Qfalse; + } + dblExp = 10.0; + while (exp) { + if (exp & 1) { + if (expSign) + frac1 /= dblExp; + else + frac1 *= dblExp; + } + exp >>= 1; + dblExp *= dblExp; + } + fraction = frac1; } - if (expSign) { - fraction = frac1 / dblExp; - } - else { - fraction = frac1 * dblExp; - } - exp = fracExp; if (exp < 0) { - expSign = TRUE; + expSign = Qtrue; exp = -exp; @@ -910,16 +898,17 @@ ruby_strtod( else { - expSign = FALSE; + expSign = Qfalse; } - dblExp = 1.0; - for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { - if (exp & 01) { - dblExp *= *d; + dblExp = 10.0; + while (exp) + { + if (exp & 1) { + if (expSign) + frac2 /= dblExp; + else + frac2 *= dblExp; } + exp >>= 1; + dblExp *= dblExp; } - if (expSign) { - fraction += frac2 / dblExp; - } - else { - fraction += frac2 * dblExp; - } + fraction += frac2; }