山本です。

[ruby-talk:99318] で報告されていたバグを修正してみました。

# 修正前(18番目以降の数字を無条件に切り捨てていた)

E:\ruby-cvs\ruby>..\miniruby -ve "p 0.0000000000000000001"
ruby 1.9.0 (2004-04-27) [i386-bccwin32]
0.0

# 修正後(有効桁数を数えるときは、先頭の 0 は数えてはいけないので、そのように修正)

E:\ruby-cvs\ruby>miniruby -e "p 0.0000000000000000001"
1e-19

Index: util.c
===================================================================
RCS file: /ruby/ruby/util.c,v
retrieving revision 1.41
diff -u -w -b -p -r1.41 util.c
--- util.c	29 Jan 2004 14:54:14 -0000	1.41
+++ util.c	6 May 2004 10:49:32 -0000
@@ -744,9 +744,10 @@ ruby_strtod(string, endPtr)
 				 * unnecessary overflow on I alone).  In this
 				 * case, fracExp is incremented one for each
 				 * dropped digit. */
-    int mantSize;		/* Number of digits in mantissa. */
-    int decPt;			/* Number of mantissa digits BEFORE decimal
-				 * point. */
+    int mantSize = 0;		/* Number of digits in mantissa. */
+    int decPt = 0;		/* mantissa has decimal point. */
+    const char *pMant;		/* Temporarily holds location of mantissa
+				 * in string. (valid only when mantSize > 0) */
     const char *pExp;		/* Temporarily holds location of exponent
 				 * in string. */
 
@@ -770,28 +771,30 @@ ruby_strtod(string, endPtr)
 	sign = FALSE;
     }
 
-    /* skip preceding zeros */
-    if (*p == '0') {
-	while (*p == '0')
-	    p++;
-	p--;
-    }
-
     /*
      * Count the number of digits in the mantissa (including the decimal
      * point), and also locate the decimal point.
      */
 
-    decPt = -1;
-    for (mantSize = 0; ; mantSize += 1) {
-	c = *p;
+    for ( ; c = *p; p++) {
 	if (!ISDIGIT(c)) {
-	    if ((c != '.') || (decPt >= 0)) {
+	    if (c != '.' || decPt) {
 		break;
 	    }
-	    decPt = mantSize;
+	    decPt = 1;
+	}
+	else {
+	    if (decPt) { /* in fractional part */
+		fracExp -= 1;
+	    }
+	    if (mantSize) { /* already in mantissa */
+		mantSize += 1;
+	    }
+	    else if (c != '0') { /* have entered mantissa */
+		mantSize += 1;
+		pMant = p;
+	    }
 	}
-	p += 1;
     }
 
     /*
@@ -802,19 +805,10 @@ ruby_strtod(string, endPtr)
      */
     
     pExp  = p;
-    p -= mantSize;
-    if (decPt < 0) {
-	decPt = mantSize;
-    }
-    else {
-	mantSize -= 1;			/* One of the digits was the point. */
-    }
+    p = pMant;
     if (mantSize > 18) {
-	fracExp = decPt - 18;
+	fracExp += (mantSize - 18);
 	mantSize = 18;
-    }
-    else {
-	fracExp = decPt - mantSize;
     }
     if (mantSize == 0) {
 	fraction = 0.0;