ruby-changes:4390
From: ko1@a...
Date: Tue, 1 Apr 2008 16:40:40 +0900 (JST)
Subject: [ruby-changes:4390] nobu - Ruby:r15881 (trunk): * bignum.c (big2dbl): more precise conversion at edge cases.
nobu 2008-04-01 16:40:23 +0900 (Tue, 01 Apr 2008)
New Revision: 15881
Modified files:
trunk/ChangeLog
trunk/bignum.c
Log:
* bignum.c (big2dbl): more precise conversion at edge cases.
[ruby-dev:34195]
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=15881&r2=15880&diff_format=u
http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/bignum.c?r1=15881&r2=15880&diff_format=u
Index: ChangeLog
===================================================================
--- ChangeLog (revision 15880)
+++ ChangeLog (revision 15881)
@@ -1,3 +1,8 @@
+Tue Apr 1 16:40:21 2008 Nobuyoshi Nakada <nobu@r...>
+
+ * bignum.c (big2dbl): more precise conversion at edge cases.
+ [ruby-dev:34195]
+
Tue Apr 1 14:43:38 2008 Nobuyoshi Nakada <nobu@r...>
* configure.in: get rid of empty expansion.
Index: bignum.c
===================================================================
--- bignum.c (revision 15880)
+++ bignum.c (revision 15881)
@@ -1133,15 +1133,64 @@
return bignorm(dbl2big(d));
}
+static int
+nlz(BDIGIT x)
+{
+ BDIGIT y;
+ int n = BITSPERDIG;
+#if BITSPERDIG > 64
+ y = x >> 64; if (y) {n -= 64; x = y;}
+#endif
+#if BITSPERDIG > 32
+ y = x >> 32; if (y) {n -= 32; x = y;}
+#endif
+#if BITSPERDIG > 16
+ y = x >> 16; if (y) {n -= 16; x = y;}
+#endif
+ y = x >> 8; if (y) {n -= 8; x = y;}
+ y = x >> 4; if (y) {n -= 4; x = y;}
+ y = x >> 2; if (y) {n -= 2; x = y;}
+ y = x >> 1; if (y) {return n - 2;}
+ return n - x;
+}
+
static double
big2dbl(VALUE x)
{
double d = 0.0;
- long i = RBIGNUM_LEN(x);
- BDIGIT *ds = BDIGITS(x);
+ long i = RBIGNUM_LEN(x), lo = 0, bits;
+ BDIGIT *ds = BDIGITS(x), dl;
- while (i--) {
- d = ds[i] + BIGRAD*d;
+ if (i) {
+ bits = i * BITSPERDIG - nlz(ds[i-1]);
+ if (bits > DBL_MANT_DIG+DBL_MAX_EXP) {
+ d = HUGE_VAL;
+ }
+ else {
+ if (bits > DBL_MANT_DIG+1)
+ lo = (bits -= DBL_MANT_DIG+1) / BITSPERDIG;
+ else
+ bits = 0;
+ while (--i > lo) {
+ d = ds[i] + BIGRAD*d;
+ }
+ dl = ds[i];
+ if (bits && (dl & (1UL << (bits %= BITSPERDIG)))) {
+ int carry = dl & ~(~0UL << bits);
+ if (!carry) {
+ while (i-- > 0) {
+ if ((carry = ds[i]) != 0) break;
+ }
+ }
+ if (carry) {
+ dl &= ~0UL << bits;
+ dl += 1UL << bits;
+ if (!dl) d += 1;
+ }
+ }
+ d = dl + BIGRAD*d;
+ if (lo) d = ldexp(d, lo * BITSPERDIG);
+ }
}
if (!RBIGNUM_SIGN(x)) d = -d;
return d;
--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/