Merge jv
authorMerge Script
Fri, 09 Oct 2015 06:49:31 +0200
branchjv
changeset 18817 080a64087e21
parent 18814 8e75e91e5e67 (current diff)
parent 18816 07540e0d0fc0 (diff)
child 18819 767041415d71
Merge
SmallInteger.st
--- a/SmallInteger.st	Wed Oct 07 06:51:59 2015 +0200
+++ b/SmallInteger.st	Fri Oct 09 06:49:31 2015 +0200
@@ -251,165 +251,193 @@
 # endif
 
     if (__isSmallInteger(aNumber)) {
-	myValue = __intVal(self);
-	otherValue = __intVal(aNumber);
+        myValue = __intVal(self);
+        otherValue = __intVal(aNumber);
 
 # if defined(USE_LONGLONG_FOR_MUL)
-	{
+        {
 #  if defined(__alpha__) && !defined(__alpha64__)
 #   define LONGLONG      INT64
 #  else
 #   define LONGLONG      long long
 #  endif
-	    LONGLONG product;
-
-	    product = (LONGLONG)myValue * (LONGLONG)otherValue;
-	    if ((product >= (LONGLONG)_MIN_INT)
-	     && (product <= (LONGLONG)_MAX_INT)) {
-		RETURN ( __mkSmallInteger((INT)product) );
-	    }
-	    if (product < 0) {
-		negative = -1;
-		product = -product;
-	    } else {
-		negative = 1;
-	    }
-	    productHi = product >> 32;
-	    productLow = product & 0xFFFFFFFFL;
-	}
+            LONGLONG product;
+
+            product = (LONGLONG)myValue * (LONGLONG)otherValue;
+            if ((product >= (LONGLONG)_MIN_INT)
+             && (product <= (LONGLONG)_MAX_INT)) {
+                RETURN ( __mkSmallInteger((INT)product) );
+            }
+            if (product < 0) {
+                negative = -1;
+                product = -product;
+            } else {
+                negative = 1;
+            }
+            productHi = product >> 32;
+            productLow = product & 0xFFFFFFFFL;
+        }
 # else /* no long-long */
-	negative = 1;
-	if (myValue < 0) {
-	    negative = -1;
-	    myValue = -myValue;
-	}
-	if (otherValue < 0) {
-	    negative = -negative;
-	    otherValue = -otherValue;
-	}
+        negative = 1;
+        if (myValue < 0) {
+            negative = -1;
+            myValue = -myValue;
+        }
+        if (otherValue < 0) {
+            negative = -negative;
+            otherValue = -otherValue;
+        }
 
 #  if defined(__GNUC__) && defined(__mc68k__)
-	asm ("mulu%.l %3,%1:%0"
-		: "=d"  ((unsigned long)(productLow)),
-		  "=d"  ((unsigned long)(productHi))
-		: "%0"  ((unsigned long)(myValue)),
-		  "dmi" ((unsigned long)(otherValue)));
+        asm ("mulu%.l %3,%1:%0"
+                : "=d"  ((unsigned long)(productLow)),
+                  "=d"  ((unsigned long)(productHi))
+                : "%0"  ((unsigned long)(myValue)),
+                  "dmi" ((unsigned long)(otherValue)));
 #  else
 #   if defined (__GNUC__) && defined(__i386__)
-	asm ("mull %3"
-		: "=a"  ((unsigned long)(productLow)),
-		  "=d"  ((unsigned long)(productHi))
-		: "%0"  ((unsigned long)(myValue)),
-		  "rm"  ((unsigned long)(otherValue)));
+        asm ("mull %3"
+                : "=a"  ((unsigned long)(productLow)),
+                  "=d"  ((unsigned long)(productHi))
+                : "%0"  ((unsigned long)(myValue)),
+                  "rm"  ((unsigned long)(otherValue)));
 #   else
 #    if defined(WIN32) && defined(__BORLANDC__)
-	asm {
-	    mov   eax, myValue
-	    mov   edx, otherValue
-	    mul   edx
-	    mov   productLow, eax
-	    mov   productHi, edx
-	}
+        asm {
+            mov   eax, myValue
+            mov   edx, otherValue
+            mul   edx
+            mov   productLow, eax
+            mov   productHi, edx
+        }
 #    else /* generic */
-	{
-	    unsigned INT pHH, pHL, pLH, pLL;
-	    unsigned INT low1, low2, hi1, hi2;
-	    unsigned INT t;
-
-	    /* unsigned multiply myValue * otherValue -> productHi, productLow
-	     *
-	     * this is too slow:
-	     * since most machines can do 32*32 to 64 bit multiply,
-	     * (or at least 32*32 with Overflow check)
-	     * - need more assembler (inline) functions here
-	     */
+        {
+            unsigned INT pHH, pHL, pLH, pLL;
+            unsigned INT low1, low2, hi1, hi2;
+            unsigned INT t;
+
+            /* unsigned multiply myValue * otherValue -> productHi, productLow
+             *
+             * this is too slow:
+             * since most machines can do 32*32 to 64 bit multiply,
+             * (or at least 32*32 with Overflow check)
+             * - need more assembler (inline) functions here
+             */
 #     if __POINTER_SIZE__ == 8
-	    low1 = low32Bits((unsigned INT)myValue);
-	    hi1 = hi32Bits((unsigned INT)myValue);
-	    low2 = low32Bits((unsigned INT)otherValue);
-	    hi2 = hi32Bits((unsigned INT)otherValue);
+            low1 = low32Bits((unsigned INT)myValue);
+            hi1 = hi32Bits((unsigned INT)myValue);
+            low2 = low32Bits((unsigned INT)otherValue);
+            hi2 = hi32Bits((unsigned INT)otherValue);
 #      define LLMASK 0xC000000000000000L
 #     else
-	    low1 = low16Bits((unsigned INT)myValue);
-	    hi1 = hi16Bits((unsigned INT)myValue);
-	    low2 = low16Bits((unsigned INT)otherValue);
-	    hi2 = hi16Bits((unsigned INT)otherValue);
+            low1 = low16Bits((unsigned INT)myValue);
+            hi1 = hi16Bits((unsigned INT)myValue);
+            low2 = low16Bits((unsigned INT)otherValue);
+            hi2 = hi16Bits((unsigned INT)otherValue);
 #      define LLMASK 0xC0000000
 #     endif
 
-	    pLH = low1 * hi2;
-	    pHL = hi1 * low2;
-	    pLL = low1 * low2;
-	    pHH = hi1 * hi2;
-
-	    /*
-	     * the common case ...
-	     */
-	    if ((pHL == 0)
-	     && (pLH == 0)
-	     && (pHH == 0)
-	     && ((pLL & LLMASK) == 0)) {
-		if (negative < 0) {
-		    RETURN ( __mkSmallInteger(- ((INT)pLL)) );
-		}
-		RETURN ( __mkSmallInteger((INT)pLL) );
-	    }
-
-	    /*
-	     *   pHH |--------|--------|
-	     *   pLH          |--------|--------|
-	     *   pHL          |--------|--------|
-	     *   pLL                   |--------|--------|
-	     */
+            pLH = low1 * hi2;
+            pHL = hi1 * low2;
+            pLL = low1 * low2;
+            pHH = hi1 * hi2;
+
+            /*
+             * the common case ...
+             */
+            if ((pHL == 0)
+             && (pLH == 0)
+             && (pHH == 0)
+             && ((pLL & LLMASK) == 0)) {
+                if (negative < 0) {
+                    RETURN ( __mkSmallInteger(- ((INT)pLL)) );
+                }
+                RETURN ( __mkSmallInteger((INT)pLL) );
+            }
+
+            /*
+             *   pHH |--------|--------|
+             *   pLH          |--------|--------|
+             *   pHL          |--------|--------|
+             *   pLL                   |--------|--------|
+             */
 
 #     if __POINTER_SIZE__ == 8
-	    t = low32Bits(pLH) + low32Bits(pHL) + hi32Bits(pLL);
-	    productLow = (t << 32) + low32Bits(pLL);
-	    productHi = pHH + hi32Bits(t) + hi32Bits(pHL) + hi32Bits(pLH);
+            t = low32Bits(pLH) + low32Bits(pHL) + hi32Bits(pLL);
+            productLow = (t << 32) + low32Bits(pLL);
+            productHi = pHH + hi32Bits(t) + hi32Bits(pHL) + hi32Bits(pLH);
 #     else
-	    t = low16Bits(pLH) + low16Bits(pHL) + hi16Bits(pLL);
-	    productLow = (t << 16) + low16Bits(pLL);
-	    productHi = pHH + hi16Bits(t) + hi16Bits(pHL) + hi16Bits(pLH);
+            t = low16Bits(pLH) + low16Bits(pHL) + hi16Bits(pLL);
+            productLow = (t << 16) + low16Bits(pLL);
+            productHi = pHH + hi16Bits(t) + hi16Bits(pHL) + hi16Bits(pLH);
 #     endif
-	}
+        }
 #    endif /* ! WIN32 */
 #   endif /* ! (__GNUC__ && __i386__) */
 #  endif /* ! (__GNUC__ && __mc68k__) */
 
-	if (productHi == 0) {
-	    if (negative < 0) {
-		if (productLow <= -(_MIN_INT)) {
-		    RETURN ( __mkSmallInteger(-((INT)productLow)) );
-		}
-	    } else {
-		if (productLow <= _MAX_INT) {
-		    RETURN ( __mkSmallInteger(productLow) );
-		}
-	    }
-	}
+        if (productHi == 0) {
+            if (negative < 0) {
+                if (productLow <= -(_MIN_INT)) {
+                    RETURN ( __mkSmallInteger(-((INT)productLow)) );
+                }
+            } else {
+                if (productLow <= _MAX_INT) {
+                    RETURN ( __mkSmallInteger(productLow) );
+                }
+            }
+        }
 # endif /* ! USE_LONGLONG */
 
 # if __POINTER_SIZE__ == 8
-	RETURN (__MKLARGEINT128(negative, productLow, productHi));
+        RETURN (__MKLARGEINT128(negative, productLow, productHi));
 # else
-	RETURN (__MKLARGEINT64(negative, productLow, productHi));
+        RETURN (__MKLARGEINT64(negative, productLow, productHi));
 # endif
     } else if (__isFloatLike(aNumber)) {
-	OBJ newFloat;
-	double val = (double)__intVal(self) * __floatVal(aNumber);
-
-	__qMKFLOAT(newFloat, val);
-	RETURN ( newFloat );
+        OBJ newFloat;
+        double val = (double)__intVal(self) * __floatVal(aNumber);
+
+        __qMKFLOAT(newFloat, val);
+        RETURN ( newFloat );
     } else if (__isShortFloat(aNumber)) {
-	OBJ newFloat;
-	float val = (float)__intVal(self) * __shortFloatVal(aNumber);
-
-	__qMKSFLOAT(newFloat, val);
-	RETURN ( newFloat );
+        OBJ newFloat;
+        float val = (float)__intVal(self) * __shortFloatVal(aNumber);
+
+        __qMKSFLOAT(newFloat, val);
+        RETURN ( newFloat );
+    } else if (__isFractionLike(aNumber)) {
+        INT myValue = __intVal(self);
+        OBJ t = __FractionInstPtr(aNumber)->f_numerator;
+
+        if (myValue == 0) {
+            RETURN(__mkSmallInteger(0));
+        }
+
+        if (__isSmallInteger(t)) {
+            INT num = __intVal(t);
+            t = __FractionInstPtr(aNumber)->f_denominator;
+            if (__isSmallInteger(t)) {
+                INT prod = myValue * num;
+                if (prod / myValue == num) { // check for overflow
+                    INT den = __intVal(t);
+                    INT quo = prod / den;
+                    if (quo * den == prod) {        // check for integer result
+                        RETURN ( __mkSmallInteger(quo) );
+                    }
+                }
+            }
+        }
     }
 #endif /* not __SCHTEAM__ */
 %}.
     ^ aNumber productFromInteger:self
+
+    "
+        3 * (1/2)
+        6 * (1/2)
+        6 * (-1/2)
+   "
 !
 
 + aNumber
@@ -593,12 +621,12 @@
      The result is truncated toward negative infinity
      and will be negative, if the operands signs differ.
      The following is always true:
-	(receiver // aNumber) * aNumber + (receiver \\ aNumber) = receiver
+        (receiver // aNumber) * aNumber + (receiver \\ aNumber) = receiver
 
      Be careful with negative results: 9 // 4 -> 2, while -9 // 4 -> -3.
      Especially surprising:
-	-1 // 10 -> -1 (because -(1/10) is truncated towards next smaller integer, which is -1.
-	-10 // 3 -> -4 (because -(10/3) is truncated towards next smaller integer, which is -4.
+        -1 // 10 -> -1 (because -(1/10) is truncated towards next smaller integer, which is -1.
+        -10 // 3 -> -4 (because -(10/3) is truncated towards next smaller integer, which is -4.
 
      See #quo: which returns -2 in the above case and #rem: which is the corresponding remainder."
 
@@ -619,60 +647,97 @@
     INT dividend, divisor, rslt;
 
     if (__isSmallInteger(aNumber)) {
-	divisor = __intVal(aNumber);
-	if (divisor != 0) {
-	    dividend = __intVal(self);
-	    rslt = dividend / divisor;
-	    /*
-	     * Optimized to speed up positive result
-	     */
-	    if (rslt <= 0) {
-		if (rslt == 0) {
-		    if ((dividend ^ divisor) < 0) {
-			/*
-			 * result (negative) has been truncated toward 0.
-			 * Return -1, because we truncate toward negative inf.
-			 */
-			 rslt = -1;
-		    }
-		} else {
-		    /*
-		     * If result (negative) has been truncated toward 0,
-		     * subtract 1, because we truncate toward negative inf.
-		     */
-		    if (divisor > 0) {
-			if (rslt * divisor > dividend) {
-			    rslt--;
-			}
-		    } else {
-			if (rslt * divisor < dividend) {
-			    rslt--;
-			}
-		    }
-		}
-	    }
-	    RETURN ( __mkSmallInteger(rslt) );
-	}
+        divisor = __intVal(aNumber);
+        if (divisor != 0) {
+            dividend = __intVal(self);
+            rslt = dividend / divisor;
+            /*
+             * Optimized to speed up positive result
+             */
+            if (rslt <= 0) {
+                if (rslt == 0) {
+                    if ((dividend ^ divisor) < 0) {
+                        /*
+                         * result (negative) has been truncated toward 0.
+                         * Return -1, because we truncate toward negative inf.
+                         */
+                         rslt = -1;
+                    }
+                } else {
+                    /*
+                     * If result (negative) has been truncated toward 0,
+                     * subtract 1, because we truncate toward negative inf.
+                     */
+                    if (divisor > 0) {
+                        if (rslt * divisor > dividend) {
+                            rslt--;
+                        }
+                    } else {
+                        if (rslt * divisor < dividend) {
+                            rslt--;
+                        }
+                    }
+                }
+            }
+            RETURN ( __mkSmallInteger(rslt) );
+        }
     } else {
-	if (__isFraction(aNumber)) {
-	    OBJ t;
-	    INT num, den;
-
-	    t = __FractionInstPtr(aNumber)->f_numerator;
-	    if (__isSmallInteger(t)) {
-		num = __intVal(t);
-		t = __FractionInstPtr(aNumber)->f_denominator;
-		if (__isSmallInteger(t)) {
-		    den = __intVal(t);
-		    RETURN ( __mkSmallInteger(__intVal(self) * den / num ));
-		}
-	    }
-	}
+        if (__isFractionLike(aNumber)) {
+            OBJ t = __FractionInstPtr(aNumber)->f_numerator;
+            if (__isSmallInteger(t)) {
+                INT num = __intVal(t);
+                t = __FractionInstPtr(aNumber)->f_denominator;
+                if (__isSmallInteger(t)) {
+                    INT den = __intVal(t);
+                    INT dividend = __intVal(self);
+                    INT prod;
+#if 0 && defined(__GNUC__) // supported from GCC 5
+                    if (!__builtin_mul_overflow(myself, den, &prod)) {
+                        goto out;   // overflow, try harder...
+                    }
+#else
+                    prod = dividend * den;
+                    // make sure, that no overflow occured
+                    if (prod / den != dividend) {
+                        goto out;   // overflow, try harder...
+                    }
+#endif
+                    rslt = prod / num;
+
+                    /*
+                     * Optimized to speed up positive result
+                     */
+                    if (rslt <= 0) {
+                        if (rslt == 0) {
+                            if ((dividend ^ num) < 0) {
+                                /*
+                                 * result (negative) has been truncated toward 0.
+                                 * Return -1, because we truncate toward negative inf.
+                                 */
+                                 rslt = -1;
+                            }
+                        } else {
+                            /*
+                             * If result (negative) has been truncated toward 0,
+                             * subtract 1, because we truncate toward negative inf.
+                             */
+                            if (num > 0) {
+                                if (rslt * num > prod) rslt--;
+                            } else {
+                                if (rslt * num < prod) rslt--;
+                            }
+                        }
+                    }
+                    RETURN ( __mkSmallInteger(rslt) );
+                }
+            }
+        }
     }
+out:;
 #endif /* not __SCHTEAM__ */
 %}.
     (aNumber = 0) ifTrue:[
-	^ ZeroDivide raiseRequestWith:thisContext.
+        ^ ZeroDivide raiseRequestWith:thisContext.
     ].
     ^ aNumber integerQuotientFromInteger:self
 
@@ -685,7 +750,17 @@
      -1 // 2    ~~ -1 ifTrue:[self halt].
      1 // -2    ~~ -1 ifTrue:[self halt].
      -1 // -2   ~~ 0 ifTrue:[self halt].
+
+     -7 // (4/3)   
+     -7 quo: (4/3)   
+
+     7 // (-4/3)   
+     7 quo: (-4/3)   
+
      10000 // 3600000 ~~ 0 ifTrue:[self halt].
+     12 // (1 / 1000000000000000000)
+     12 // (1 / 100000000000000)
+     12 // 0.00000000000001s
 
      9 quo:4   => 2
      -9 quo:4  => -2
@@ -826,7 +901,7 @@
      and the arguments value. The result is truncated towards zero
      and negative, if the operands signs differ..
      The following is always true:
-	(receiver quo: aNumber) * aNumber + (receiver rem: aNumber) = receiver
+        (receiver quo: aNumber) * aNumber + (receiver rem: aNumber) = receiver
      For positive results, this is the same as #//,
      for negative results, the remainder is ignored.
      I.e.: '9 // 4 = 2' and '-9 // 4 = -3'
@@ -836,33 +911,40 @@
 #ifdef __SCHTEAM__
     return context._RETURN( self.quotient(aNumber));
 #else
-    INT val;
-
     if (__isSmallInteger(aNumber)) {
-	val = __intVal(aNumber);
-	if (val != 0) {
-	    RETURN ( __mkSmallInteger(__intVal(self) / val) );
-	}
+        INT val = __intVal(aNumber);
+        if (val != 0) {
+            RETURN ( __mkSmallInteger(__intVal(self) / val) );
+        }
     } else {
-	if (__isFraction(aNumber)) {
-	    OBJ t;
-	    INT num, den;
-
-	    t = __FractionInstPtr(aNumber)->f_numerator;
-	    if (__isSmallInteger(t)) {
-		num = __intVal(t);
-		t = __FractionInstPtr(aNumber)->f_denominator;
-		if (__isSmallInteger(t)) {
-		    den = __intVal(t);
-		    RETURN ( __mkSmallInteger(__intVal(self) * den / num ));
-		}
-	    }
-	}
+        if (__isFractionLike(aNumber)) {
+            OBJ t = __FractionInstPtr(aNumber)->f_numerator;
+            if (__isSmallInteger(t)) {
+                INT num = __intVal(t);
+                t = __FractionInstPtr(aNumber)->f_denominator;
+                if (__isSmallInteger(t)) {
+                    INT den = __intVal(t);
+                    INT myself = __intVal(self);
+                    INT prod;
+#if 0 && defined(__GNUC__) // supported from GCC 5
+                    if (__builtin_mul_overflow(myself, den, &prod)) {
+                        RETURN ( __mkSmallInteger(prod / num ));
+                    }
+#else
+                    prod = myself * den;
+                    // make sure, that no overflow occured
+                    if (prod / den == myself) {
+                        RETURN ( __mkSmallInteger(prod / num ));
+                    }
+#endif
+                }
+            }
+        }
     }
 #endif /* not __SCHTEAM__ */
 %}.
     (aNumber = 0) ifTrue:[
-	^ ZeroDivide raiseRequestWith:thisContext.
+        ^ ZeroDivide raiseRequestWith:thisContext.
     ].
     ^ self retry:#quo: coercing:aNumber
 
@@ -871,10 +953,17 @@
      -9 // 4
      9 quo:4
      -9 quo:4
+
+     -7 // (4/3)   
+     -7 quo: (4/3)   
+
+     7 // (-4/3)   
+     7 quo: (-4/3)   
     "
 ! !
 
 
+
 !SmallInteger methodsFor:'bit operators'!
 
 bitAnd:anInteger