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

ruby-changes:15247

From: akr <ko1@a...>
Date: Wed, 31 Mar 2010 23:35:37 +0900 (JST)
Subject: [ruby-changes:15247] Ruby:r27129 (trunk): * time.c (long_mul): extracted from mul and avoid integer overflow.

akr	2010-03-31 23:35:13 +0900 (Wed, 31 Mar 2010)

  New Revision: 27129

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=27129

  Log:
    * time.c (long_mul): extracted from mul and avoid integer overflow.
      (wi_mul): extracted from wmul and avoid integer overflow.

  Modified files:
    trunk/ChangeLog
    trunk/time.c

Index: time.c
===================================================================
--- time.c	(revision 27128)
+++ time.c	(revision 27129)
@@ -78,6 +78,50 @@
     return rb_funcall(x, '-', 1, y);
 }
 
+#if !(HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG)
+static int
+long_mul(long x, long y, long *z)
+{
+    unsigned long a, b, c;
+    int s;
+    if (x == 0 || y == 0) {
+	*z = 0;
+	return 1;
+    }
+    if (x < 0) {
+	s = -1;
+	a = (unsigned long)-x;
+    }
+    else {
+	s = 1;
+	a = (unsigned long)x;
+    }
+    if (y < 0) {
+        s = -s;
+	b = (unsigned long)-y;
+    }
+    else {
+	b = (unsigned long)y;
+    }
+    c = a * b;
+    if (c / b == a) {
+	if (s < 0) {
+	    if (c <= (unsigned long)LONG_MAX + 1) {
+		*z = -(long)c;
+		return 1;
+	    }
+	}
+	else {
+	    if (c <= (unsigned long)LONG_MAX) {
+		*z = (long)c;
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+#endif
+
 static VALUE
 mul(VALUE x, VALUE y)
 {
@@ -88,14 +132,9 @@
             return LONG2FIX(ll);
         return LL2NUM(ll);
 #else
-        long a, b, c;
-        a = FIX2LONG(x);
-        if (a == 0)
-            return x;
-        b = FIX2LONG(y);
-        c = a * b;
-        if (c / a == b)
-            return LONG2NUM(c);
+	long z;
+	if (long_mul(FIX2LONG(x), FIX2LONG(y), &z))
+	    return LONG2NUM(z);
 #endif
     }
     if (TYPE(x) == T_BIGNUM)
@@ -171,13 +210,14 @@
     typedef uint64_t WIDEVALUE;
     typedef int64_t SIGNED_WIDEVALUE;
 #   define WIDEVALUE_IS_WIDER 1
+#   define UWIDEINT_MAX UINT64_MAX
+#   define WIDEINT_MAX INT64_MAX
+#   define WIDEINT_MIN INT64_MIN
 #   define FIXWINT_P(tv) ((tv) & 1)
 #   define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1)
 #   define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG))
 #   define FIXWV_MAX (((int64_t)1 << 62) - 1)
 #   define FIXWV_MIN (-((int64_t)1 << 62))
-#   define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
-#   define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
 #   define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi))
 #   define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i))
 #   define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w))
@@ -187,15 +227,23 @@
     typedef VALUE WIDEVALUE;
     typedef SIGNED_VALUE SIGNED_WIDEVALUE;
 #   define WIDEVALUE_IS_WIDER 0
+#   define UWIDEINT_MAX ULONG_MAX
+#   define WIDEINT_MAX LONG_MAX
+#   define WIDEINT_MIN LONG_MIN
 #   define FIXWINT_P(v) FIXNUM_P(v)
+#   define FIXWV_MAX FIXNUM_MAX
+#   define FIXWV_MIN FIXNUM_MIN
 #   define FIXWVABLE(i) FIXABLE(i)
 #   define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i))
 #   define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w))
 #endif
 
+#define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
+#define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
 #define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w))
 
 /* #define STRUCT_WIDEVAL */
+#define STRUCT_WIDEVAL
 #ifdef STRUCT_WIDEVAL
     /* for type checking */
     typedef struct {
@@ -406,20 +454,57 @@
     return v2w(rb_funcall(x, '-', 1, w2v(wy)));
 }
 
+static int
+wi_mul(wideint_t x, wideint_t y, wideint_t *z)
+{
+    uwideint_t a, b, c;
+    int s;
+    if (x == 0 || y == 0) {
+	*z = 0;
+	return 1;
+    }
+    if (x < 0) {
+	s = -1;
+	a = (uwideint_t)-x;
+    }
+    else {
+	s = 1;
+	a = (uwideint_t)x;
+    }
+    if (y < 0) {
+        s = -s;
+	b = (uwideint_t)-y;
+    }
+    else {
+	b = (uwideint_t)y;
+    }
+    c = a * b;
+    if (c / b == a) {
+	if (s < 0) {
+	    if (c <= (uwideint_t)WIDEINT_MAX + 1) {
+		*z = -(wideint_t)c;
+		return 1;
+	    }
+	}
+	else {
+	    if (c <= (uwideint_t)WIDEINT_MAX) {
+		*z = (wideint_t)c;
+		return 1;
+	    }
+	}
+    }
+    return 0;
+}
+
 static wideval_t
 wmul(wideval_t wx, wideval_t wy)
 {
     VALUE x, z;
 #if WIDEVALUE_IS_WIDER
     if (FIXWV_P(wx) && FIXWV_P(wy)) {
-        wideint_t a, b, c;
-        a = FIXWV2WINT(wx);
-        if (a == 0) return wx;
-        b = FIXWV2WINT(wy);
-        c = a * b;
-        if (c / a == b) {
-            return WINT2WV(c);
-        }
+	wideint_t z;
+	if (wi_mul(FIXWV2WINT(wx), FIXWV2WINT(wy), &z))
+	    return WINT2WV(z);
     }
 #endif
     x = w2v(wx);
@@ -643,18 +728,9 @@
 rb_time_magnify(wideval_t w)
 {
     if (FIXWV_P(w)) {
-        wideint_t a, b, c;
-        a = FIXWV2WINT(w);
-        if (a == 0) {
-            return WINT2FIXWV(0);
-	}
-        b = TIME_SCALE;
-        c = a * b;
-        if (c / b == a) {
-            if (FIXWVABLE(c)) {
-                return WINT2FIXWV(c);
-            }
-        }
+	wideint_t z;
+	if (wi_mul(FIXWV2WINT(w), TIME_SCALE, &z))
+	    return WINT2WV(z);
     }
     return wmul(w, WINT2FIXWV(TIME_SCALE));
 }
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 27128)
+++ ChangeLog	(revision 27129)
@@ -1,3 +1,8 @@
+Wed Mar 31 23:33:29 2010  Tanaka Akira  <akr@f...>
+
+	* time.c (long_mul): extracted from mul and avoid integer overflow.
+	  (wi_mul): extracted from wmul and avoid integer overflow.
+
 Wed Mar 31 21:30:38 2010  Tanaka Akira  <akr@f...>
 
 	* time.c: less bignum allocations.

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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