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 |