[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]