From: "H.Yamamoto" Date: 2004-05-08T18:56:54+09:00 Subject: [ruby-dev:23484] Re: [BUG] numeric.c (flo_to_s) broken? 山本です。 doubleの有効桁が15である保証はなかったので、少し修正しました。 自分でもどこが違うのかよくわからなくなったため、整理してみました。 下の実行結果は、一番上が 1.101.2.4、真中が 1.101.2.5(lastest)、一番下が私のパッチです。 (ruby_1_8 ブランチです)なお、私の環境では DBL_DIG == 15 です。 E:\ruby-cvs>a 0.000000001 1.0e-09 1.0000000000000001e-09 1.0e-09 E:\ruby-cvs>a 0.0000000001 1.0e-10 1.0e-10 1.0e-10 E:\ruby-cvs>a 0.00000000001 1e-11 9.9999999999999994e-12 1.0e-11 1.101.2.4 では、書式が e-11 から変化している。(コードをよく見てないので、理由は不明) 1.101.2.5 では、有効でない桁の数字(16番目以降)を表示しようとするため、意図と違う表示がされている。 これに対する修正は [ruby-dev:23482] の DBL_DIG 考慮版で十分かもしれません。 ///////////////////////////////////////////////////////////////////////////////// E:\ruby-cvs>a 1.1111222223333344444e-7 1.11112222233333e-07 0.000000111112222 0.000000111112222233333 1.101.2.5 では、有効桁数が減っている。 ///////////////////////////////////////////////////////////////////////////////// E:\ruby-cvs>a 11111222223333344444.0 1.1111222223333345e+19 1.1111222223333345e+19 1.11112222233333e+19 1.101.2.4 と 1.101.2.5 で、有効桁数が増えている。 ///////////////////////////////////////////////////////////////////////////////// * 有効桁の外の数字を表示しないようにした。 Index: numeric.c =================================================================== RCS file: /ruby/ruby/numeric.c,v retrieving revision 1.101.2.5 diff -u -w -b -p -r1.101.2.5 numeric.c --- numeric.c 7 May 2004 08:48:20 -0000 1.101.2.5 +++ numeric.c 8 May 2004 09:22:18 -0000 @@ -488,10 +488,9 @@ static VALUE flo_to_s(flt) VALUE flt; { - char buf[32]; - char *fmt = "%.15f"; + char buf[32], fmt[32]; double value = RFLOAT(flt)->value; - double avalue, d1, d2; + int exp; char *p, *e; if (isinf(value)) @@ -499,13 +498,25 @@ flo_to_s(flt) else if(isnan(value)) return rb_str_new2("NaN"); - avalue = fabs(value); - if (avalue < 1.0e-7 || avalue >= 1.0e15) { - fmt = "%.16e"; - } + sprintf(fmt, "%%.%de", DBL_DIG - 1); sprintf(buf, fmt, value); - if (!(e = strchr(buf, 'e'))) { - e = buf + strlen(buf); + e = strchr(buf, 'e'); + exp = atoi(e+1); + if (-7 <= exp && exp < DBL_DIG - 1) { + char *d = strchr(buf, '.'); + if (exp > 0) { + memmove(d, d+1, exp); + d[exp] = '.'; + } + if (exp < 0) { + int n = -exp; + d[0] = d[-1]; + memmove(d+n, d, strlen(d)+1); + e += n; + memset(buf, '0', n+1); + buf[1] = '.'; + } + *e = '\0'; } p = e; while (*--p=='0')