SmallInteger.st
branchjv
changeset 20342 219a5a47e8b1
parent 20143 c64b16f62536
parent 20262 ffae5acd468c
child 20345 68e5382ae472
equal deleted inserted replaced
20248:34ed3b6c7307 20342:219a5a47e8b1
   619     "return the integer part of the quotient of the receiver's value
   619     "return the integer part of the quotient of the receiver's value
   620      and the argument's value.
   620      and the argument's value.
   621      The result is truncated toward negative infinity
   621      The result is truncated toward negative infinity
   622      and will be negative, if the operands signs differ.
   622      and will be negative, if the operands signs differ.
   623      The following is always true:
   623      The following is always true:
   624 	(receiver // aNumber) * aNumber + (receiver \\ aNumber) = receiver
   624         (receiver // aNumber) * aNumber + (receiver \\ aNumber) = receiver
   625 
   625 
   626      Be careful with negative results: 9 // 4 -> 2, while -9 // 4 -> -3.
   626      Be careful with negative results: 9 // 4 -> 2, while -9 // 4 -> -3.
   627      Especially surprising:
   627      Especially surprising:
   628 	-1 // 10 -> -1 (because -(1/10) is truncated towards next smaller integer, which is -1.
   628         -1 // 10 -> -1 (because -(1/10) is truncated towards next smaller integer, which is -1.
   629 	-10 // 3 -> -4 (because -(10/3) is truncated towards next smaller integer, which is -4.
   629         -10 // 3 -> -4 (because -(10/3) is truncated towards next smaller integer, which is -4.
   630 
   630 
   631      See #quo: which returns -2 in the above case and #rem: which is the corresponding remainder."
   631      See #quo: which returns -2 in the above case and #rem: which is the corresponding remainder."
   632 
   632 
   633 %{  /* NOCONTEXT */
   633 %{  /* NOCONTEXT */
   634 #ifdef __SCHTEAM__
   634 #ifdef __SCHTEAM__
   646 
   646 
   647     INT divisor, rslt;
   647     INT divisor, rslt;
   648     INT dividend = __intVal(self);
   648     INT dividend = __intVal(self);
   649 
   649 
   650     if (__isSmallInteger(aNumber)) {
   650     if (__isSmallInteger(aNumber)) {
   651 	divisor = __intVal(aNumber);
   651         divisor = __intVal(aNumber);
   652 	if (divisor != 0) {
   652         if (divisor != 0) {
   653 	    rslt = dividend / divisor;
   653             rslt = dividend / divisor;
   654 	    /*
   654             /*
   655 	     * Optimized to speed up positive result
   655              * Optimized to speed up positive result
   656 	     */
   656              */
   657 	    if (rslt <= 0) {
   657             if (rslt <= 0) {
   658 		if (rslt == 0) {
   658                 if (rslt == 0) {
   659 		    if ((dividend ^ divisor) < 0) {
   659                     if ((dividend ^ divisor) < 0) {
   660 			/*
   660                         /*
   661 			 * result (negative) has been truncated toward 0.
   661                          * result (negative) has been truncated toward 0.
   662 			 * Return -1, because we truncate toward negative inf.
   662                          * Return -1, because we truncate toward negative inf.
   663 			 */
   663                          */
   664 			 rslt = -1;
   664                          rslt = -1;
   665 		    }
   665                     }
   666 		} else {
   666                 } else {
   667 		    /*
   667                     /*
   668 		     * If result (negative) has been truncated toward 0,
   668                      * If result (negative) has been truncated toward 0,
   669 		     * subtract 1, because we truncate toward negative inf.
   669                      * subtract 1, because we truncate toward negative inf.
   670 		     */
   670                      */
   671 		    if (divisor > 0) {
   671                     if (divisor > 0) {
   672 			if (rslt * divisor > dividend) {
   672                         if (rslt * divisor > dividend) {
   673 			    rslt--;
   673                             rslt--;
   674 			}
   674                         }
   675 		    } else {
   675                     } else {
   676 			if (rslt * divisor < dividend) {
   676                         if (rslt * divisor < dividend) {
   677 			    rslt--;
   677                             rslt--;
   678 			}
   678                         }
   679 		    }
   679                     }
   680 		}
   680                 }
   681 	    }
   681             }
   682 	    RETURN ( __mkSmallInteger(rslt) );
   682             RETURN ( __mkSmallInteger(rslt) );
   683 	}
   683         }
   684     } else {
   684     } else {
   685 	if (__isFractionLike(aNumber)) {
   685         if (__isFractionLike(aNumber)) {
   686 	    OBJ t = __FractionInstPtr(aNumber)->f_numerator;
   686             OBJ t = __FractionInstPtr(aNumber)->f_numerator;
   687 	    if (__isSmallInteger(t)) {
   687             if (__isSmallInteger(t)) {
   688 		INT num = __intVal(t);
   688                 INT num = __intVal(t);
   689 		t = __FractionInstPtr(aNumber)->f_denominator;
   689                 t = __FractionInstPtr(aNumber)->f_denominator;
   690 		if (__isSmallInteger(t)) {
   690                 if (__isSmallInteger(t)) {
   691 		    INT den = __intVal(t);
   691                     INT den = __intVal(t);
   692 		    INT prod;
   692                     INT prod;
   693 #if 0 && defined(__GNUC__) // supported from GCC 5
   693 #if 0 && defined(__GNUC__) // supported from GCC 5
   694 		    if (!__builtin_mul_overflow(myself, den, &prod)) {
   694                     if (!__builtin_mul_overflow(myself, den, &prod)) {
   695 			goto out;   // overflow, try harder...
   695                         goto out;   // overflow, try harder...
   696 		    }
   696                     }
   697 #else
   697 #else
   698 		    prod = dividend * den;
   698                     prod = dividend * den;
   699 		    // make sure, that no overflow occured
   699                     // make sure, that no overflow occurred
   700 		    if (prod / den != dividend) {
   700                     if (prod / den != dividend) {
   701 			goto out;   // overflow, try harder...
   701                         goto out;   // overflow, try harder...
   702 		    }
   702                     }
   703 #endif
   703 #endif
   704 		    rslt = prod / num;
   704                     rslt = prod / num;
   705 
   705 
   706 		    /*
   706                     /*
   707 		     * Optimized to speed up positive result
   707                      * Optimized to speed up positive result
   708 		     */
   708                      */
   709 		    if (rslt <= 0) {
   709                     if (rslt <= 0) {
   710 			if (rslt == 0) {
   710                         if (rslt == 0) {
   711 			    if ((dividend ^ num) < 0) {
   711                             if ((dividend ^ num) < 0) {
   712 				/*
   712                                 /*
   713 				 * result (negative) has been truncated toward 0.
   713                                  * result (negative) has been truncated toward 0.
   714 				 * Return -1, because we truncate toward negative inf.
   714                                  * Return -1, because we truncate toward negative inf.
   715 				 */
   715                                  */
   716 				 rslt = -1;
   716                                  rslt = -1;
   717 			    }
   717                             }
   718 			} else {
   718                         } else {
   719 			    /*
   719                             /*
   720 			     * If result (negative) has been truncated toward 0,
   720                              * If result (negative) has been truncated toward 0,
   721 			     * subtract 1, because we truncate toward negative inf.
   721                              * subtract 1, because we truncate toward negative inf.
   722 			     */
   722                              */
   723 			    if (num > 0) {
   723                             if (num > 0) {
   724 				if (rslt * num > prod) rslt--;
   724                                 if (rslt * num > prod) rslt--;
   725 			    } else {
   725                             } else {
   726 				if (rslt * num < prod) rslt--;
   726                                 if (rslt * num < prod) rslt--;
   727 			    }
   727                             }
   728 			}
   728                         }
   729 		    }
   729                     }
   730 		    RETURN ( __mkSmallInteger(rslt) );
   730                     RETURN ( __mkSmallInteger(rslt) );
   731 		}
   731                 }
   732 	    }
   732             }
   733 	}
   733         }
   734     }
   734     }
   735 out:;
   735 out:;
   736 #endif /* not __SCHTEAM__ */
   736 #endif /* not __SCHTEAM__ */
   737 %}.
   737 %}.
   738     (aNumber = 0) ifTrue:[
   738     (aNumber = 0) ifTrue:[
   739 	^ ZeroDivide raiseRequestWith:thisContext.
   739         ^ ZeroDivide raiseRequestWith:thisContext.
   740     ].
   740     ].
   741     ^ aNumber integerQuotientFromInteger:self
   741     ^ aNumber integerQuotientFromInteger:self
   742 
   742 
   743     "
   743     "
   744      9 // 4     ~~ 2 ifTrue:[self halt].
   744      9 // 4     ~~ 2 ifTrue:[self halt].
   898 quo:aNumber
   898 quo:aNumber
   899     "return the integer part of the quotient of the receiver's value
   899     "return the integer part of the quotient of the receiver's value
   900      and the argument's value. The result is truncated towards zero
   900      and the argument's value. The result is truncated towards zero
   901      and negative, if the operands signs differ..
   901      and negative, if the operands signs differ..
   902      The following is always true:
   902      The following is always true:
   903 	(receiver quo: aNumber) * aNumber + (receiver rem: aNumber) = receiver
   903         (receiver quo: aNumber) * aNumber + (receiver rem: aNumber) = receiver
   904      For positive results, this is the same as #//,
   904      For positive results, this is the same as #//,
   905      for negative results, the remainder is ignored.
   905      for negative results, the remainder is ignored.
   906      I.e.: '9 // 4 = 2' and '-9 // 4 = -3'
   906      I.e.: '9 // 4 = 2' and '-9 // 4 = -3'
   907      in contrast: '9 quo: 4 = 2' and '-9 quo: 4 = -2'"
   907      in contrast: '9 quo: 4 = 2' and '-9 quo: 4 = -2'"
   908 
   908 
   909 %{  /* NOCONTEXT */
   909 %{  /* NOCONTEXT */
   910 #ifdef __SCHTEAM__
   910 #ifdef __SCHTEAM__
   911     return context._RETURN( self.quotient(aNumber));
   911     return context._RETURN( self.quotient(aNumber));
   912 #else
   912 #else
   913     if (__isSmallInteger(aNumber)) {
   913     if (__isSmallInteger(aNumber)) {
   914 	INT val = __intVal(aNumber);
   914         INT val = __intVal(aNumber);
   915 	if (val != 0) {
   915         if (val != 0) {
   916 	    RETURN ( __mkSmallInteger(__intVal(self) / val) );
   916             RETURN ( __mkSmallInteger(__intVal(self) / val) );
   917 	}
   917         }
   918     } else {
   918     } else {
   919 	if (__isFractionLike(aNumber)) {
   919         if (__isFractionLike(aNumber)) {
   920 	    OBJ t = __FractionInstPtr(aNumber)->f_numerator;
   920             OBJ t = __FractionInstPtr(aNumber)->f_numerator;
   921 	    if (__isSmallInteger(t)) {
   921             if (__isSmallInteger(t)) {
   922 		INT num = __intVal(t);
   922                 INT num = __intVal(t);
   923 		t = __FractionInstPtr(aNumber)->f_denominator;
   923                 t = __FractionInstPtr(aNumber)->f_denominator;
   924 		if (__isSmallInteger(t)) {
   924                 if (__isSmallInteger(t)) {
   925 		    INT den = __intVal(t);
   925                     INT den = __intVal(t);
   926 		    INT myself = __intVal(self);
   926                     INT myself = __intVal(self);
   927 		    INT prod;
   927                     INT prod;
   928 #if 0 && defined(__GNUC__) // supported from GCC 5
   928 #if 0 && defined(__GNUC__) // supported from GCC 5
   929 		    if (__builtin_mul_overflow(myself, den, &prod)) {
   929                     if (__builtin_mul_overflow(myself, den, &prod)) {
   930 			RETURN ( __mkSmallInteger(prod / num ));
   930                         RETURN ( __mkSmallInteger(prod / num ));
   931 		    }
   931                     }
   932 #else
   932 #else
   933 		    prod = myself * den;
   933                     prod = myself * den;
   934 		    // make sure, that no overflow occured
   934                     // make sure, that no overflow occurred
   935 		    if (prod / den == myself) {
   935                     if (prod / den == myself) {
   936 			RETURN ( __mkSmallInteger(prod / num ));
   936                         RETURN ( __mkSmallInteger(prod / num ));
   937 		    }
   937                     }
   938 #endif
   938 #endif
   939 		}
   939                 }
   940 	    }
   940             }
   941 	}
   941         }
   942     }
   942     }
   943 #endif /* not __SCHTEAM__ */
   943 #endif /* not __SCHTEAM__ */
   944 %}.
   944 %}.
   945     (aNumber = 0) ifTrue:[
   945     (aNumber = 0) ifTrue:[
   946 	^ ZeroDivide raiseRequestWith:thisContext.
   946         ^ ZeroDivide raiseRequestWith:thisContext.
   947     ].
   947     ].
   948     ^ self retry:#quo: coercing:aNumber
   948     ^ self retry:#quo: coercing:aNumber
   949 
   949 
   950     "
   950     "
   951      9 // 4
   951      9 // 4