@@ -80,6 +80,7 @@ final class RuntimeLong(val lo: Int, val hi: Int) {
80
80
@ inlineprivate def >>> (b :Int ): RuntimeLong = RuntimeLong .shr(this , b)
81
81
@ inlineprivate def + (b :RuntimeLong ): RuntimeLong = RuntimeLong .add(this , b)
82
82
@ inlineprivate def - (b :RuntimeLong ): RuntimeLong = RuntimeLong .sub(this , b)
83
+ @ inlineprivate def * (b :RuntimeLong ): RuntimeLong = RuntimeLong .mul(this , b)
83
84
}
84
85
85
86
object RuntimeLong {
@@ -916,37 +917,11 @@ object RuntimeLong {
916
917
}
917
918
918
919
def divideImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int = {
919
- if (isZero(blo, bhi))
920
- throw new ArithmeticException (" / by zero" )
921
-
922
- if (isInt32(alo, ahi)) {
923
- if (isInt32(blo, bhi)) {
924
- if (alo== Int .MinValue && blo== - 1 ) {
925
- hiReturn= 0
926
- Int .MinValue
927
- }else {
928
- val lo = alo/ blo
929
- hiReturn= lo>> 31
930
- lo
931
- }
932
- }else {
933
- // Either a == Int.MinValue && b == (Int.MaxValue + 1), or (abs(b) > abs(a))
934
- if (alo== Int .MinValue && (blo== 0x80000000 && bhi== 0 )) {
935
- hiReturn= - 1
936
- - 1
937
- }else {
938
- // 0L, because abs(b) > abs(a)
939
- hiReturn= 0
940
- 0
941
- }
942
- }
943
- }else {
944
- val aAbs = inline_abs(alo, ahi)
945
- val bAbs = inline_abs(blo, bhi)
946
- val absRLo = unsigned_/(aAbs.lo, aAbs.hi, bAbs.lo, bAbs.hi)
947
- if ((ahi^ bhi)>= 0 ) absRLo// a and b have the same sign bit
948
- else inline_negate_hiReturn(absRLo, hiReturn)
949
- }
920
+ val aAbs = inline_abs(alo, ahi)
921
+ val bAbs = inline_abs(blo, bhi)
922
+ val absRLo = unsigned_/(aAbs.lo, aAbs.hi, bAbs.lo, bAbs.hi)
923
+ if ((ahi^ bhi)>= 0 ) absRLo// a and b have the same sign bit
924
+ else inline_negate_hiReturn(absRLo, hiReturn)
950
925
}
951
926
952
927
@ inline
@@ -955,52 +930,13 @@ object RuntimeLong {
955
930
new RuntimeLong (lo, hiReturn)
956
931
}
957
932
958
- def divideUnsignedImpl ( alo : Int , ahi : Int , blo : Int , bhi : Int ) : Int = {
959
- if (isZero( blo, bhi))
960
- throw new ArithmeticException ( " / by zero " )
933
+ @ inline
934
+ def divideUnsignedImpl ( alo : Int , ahi : Int , blo : Int ,bhi : Int ) : Int =
935
+ unsigned_/(alo, ahi, blo, bhi )
961
936
962
- if (isUInt32(ahi)) {
963
- if (isUInt32(bhi)) {
964
- hiReturn= 0
965
- Integer .divideUnsigned(alo, blo)
966
- }else {
967
- // a < b
968
- hiReturn= 0
969
- 0
970
- }
971
- }else {
972
- unsigned_/(alo, ahi, blo, bhi)
973
- }
974
- }
975
-
976
- private def unsigned_/ (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int = {
977
- // This method is not called if isInt32(alo, ahi) nor if isZero(blo, bhi)
978
- if (isUnsignedSafeDouble(ahi)) {
979
- if (isUnsignedSafeDouble(bhi)) {
980
- val aDouble = asUnsignedSafeDouble(alo, ahi)
981
- val bDouble = asUnsignedSafeDouble(blo, bhi)
982
- val rDouble = aDouble/ bDouble
983
- hiReturn= unsignedSafeDoubleHi(rDouble)
984
- unsignedSafeDoubleLo(rDouble)
985
- }else {
986
- // 0L, because b > a
987
- hiReturn= 0
988
- 0
989
- }
990
- }else {
991
- if (bhi== 0 && isPowerOfTwo_IKnowItsNot0(blo)) {
992
- val pow = log2OfPowerOfTwo(blo)
993
- hiReturn= ahi>>> pow
994
- (alo>>> pow)| (ahi<< 1 << (31 - pow))
995
- }else if (blo== 0 && isPowerOfTwo_IKnowItsNot0(bhi)) {
996
- val pow = log2OfPowerOfTwo(bhi)
997
- hiReturn= 0
998
- ahi>>> pow
999
- }else {
1000
- unsignedDivModHelper(alo, ahi, blo, bhi, askQuotient= true )
1001
- }
1002
- }
1003
- }
937
+ @ noinline
938
+ private def unsigned_/ (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
939
+ unsignedDivModHelper(alo, ahi, blo, bhi, askQuotient= true )
1004
940
1005
941
@ inline
1006
942
def remainder (a :RuntimeLong ,b :RuntimeLong ): RuntimeLong = {
@@ -1009,38 +945,11 @@ object RuntimeLong {
1009
945
}
1010
946
1011
947
def remainderImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int = {
1012
- if (isZero(blo, bhi))
1013
- throw new ArithmeticException (" / by zero" )
1014
-
1015
- if (isInt32(alo, ahi)) {
1016
- if (isInt32(blo, bhi)) {
1017
- if (blo!= - 1 ) {
1018
- val lo = alo% blo
1019
- hiReturn= lo>> 31
1020
- lo
1021
- }else {
1022
- // Work around https://github.com/ariya/phantomjs/issues/12198
1023
- hiReturn= 0
1024
- 0
1025
- }
1026
- }else {
1027
- // Either a == Int.MinValue && b == (Int.MaxValue + 1), or (abs(b) > abs(a))
1028
- if (alo== Int .MinValue && (blo== 0x80000000 && bhi== 0 )) {
1029
- hiReturn= 0
1030
- 0
1031
- }else {
1032
- // a, because abs(b) > abs(a)
1033
- hiReturn= ahi
1034
- alo
1035
- }
1036
- }
1037
- }else {
1038
- val aAbs = inline_abs(alo, ahi)
1039
- val bAbs = inline_abs(blo, bhi)
1040
- val absRLo = unsigned_%(aAbs.lo, aAbs.hi, bAbs.lo, bAbs.hi)
1041
- if (ahi< 0 ) inline_negate_hiReturn(absRLo, hiReturn)
1042
- else absRLo
1043
- }
948
+ val aAbs = inline_abs(alo, ahi)
949
+ val bAbs = inline_abs(blo, bhi)
950
+ val absRLo = unsigned_%(aAbs.lo, aAbs.hi, bAbs.lo, bAbs.hi)
951
+ if (ahi< 0 ) inline_negate_hiReturn(absRLo, hiReturn)
952
+ else absRLo
1044
953
}
1045
954
1046
955
@ inline
@@ -1049,122 +958,74 @@ object RuntimeLong {
1049
958
new RuntimeLong (lo, hiReturn)
1050
959
}
1051
960
1052
- def remainderUnsignedImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int = {
1053
- if (isZero(blo, bhi))
1054
- throw new ArithmeticException (" / by zero" )
1055
-
1056
- if (isUInt32(ahi)) {
1057
- if (isUInt32(bhi)) {
1058
- hiReturn= 0
1059
- Integer .remainderUnsigned(alo, blo)
1060
- }else {
1061
- // a < b
1062
- hiReturn= ahi
1063
- alo
1064
- }
1065
- }else {
1066
- unsigned_%(alo, ahi, blo, bhi)
1067
- }
1068
- }
961
+ @ inline
962
+ private def remainderUnsignedImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
963
+ unsigned_%(alo, ahi, blo, bhi)
1069
964
1070
- private def unsigned_% (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int = {
1071
- // This method is not called if isInt32(alo, ahi) nor if isZero(blo, bhi)
1072
- if (isUnsignedSafeDouble(ahi)) {
1073
- if (isUnsignedSafeDouble(bhi)) {
1074
- val aDouble = asUnsignedSafeDouble(alo, ahi)
1075
- val bDouble = asUnsignedSafeDouble(blo, bhi)
1076
- val rDouble = aDouble% bDouble
1077
- hiReturn= unsignedSafeDoubleHi(rDouble)
1078
- unsignedSafeDoubleLo(rDouble)
1079
- }else {
1080
- // a, because b > a
1081
- hiReturn= ahi
1082
- alo
1083
- }
1084
- }else {
1085
- if (bhi== 0 && isPowerOfTwo_IKnowItsNot0(blo)) {
1086
- hiReturn= 0
1087
- alo& (blo- 1 )
1088
- }else if (blo== 0 && isPowerOfTwo_IKnowItsNot0(bhi)) {
1089
- hiReturn= ahi& (bhi- 1 )
1090
- alo
1091
- }else {
1092
- unsignedDivModHelper(alo, ahi, blo, bhi, askQuotient= false )
1093
- }
1094
- }
1095
- }
965
+ @ noinline
966
+ private def unsigned_% (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
967
+ unsignedDivModHelper(alo, ahi, blo, bhi, askQuotient= false )
1096
968
1097
969
/** Helper for `unsigned_/` and `unsigned_%`.
1098
970
*
1099
971
* If `askQuotient` is true, computes the quotient, otherwise computes the
1100
972
* remainder. Stores the hi word of the result in `hiReturn`, and returns
1101
973
* the lo word.
1102
974
*/
975
+ @ inline
1103
976
private def unsignedDivModHelper (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ,
1104
977
askQuotient :Boolean ): Int = {
1105
978
1106
- var shift =
1107
- inlineNumberOfLeadingZeros(blo, bhi)- inlineNumberOfLeadingZeros(alo, ahi)
1108
- val initialBShift = new RuntimeLong (blo, bhi)<< shift
1109
- var bShiftLo = initialBShift.lo
1110
- var bShiftHi = initialBShift.hi
1111
- var remLo = alo
1112
- var remHi = ahi
1113
- var quotLo = 0
1114
- var quotHi = 0
1115
-
1116
- /* Invariants:
1117
- * bShift == b << shift == b * 2^shift
1118
- * quot >= 0
1119
- * 0 <= rem < 2 * bShift
1120
- * quot * b + rem == a
1121
- *
1122
- * The loop condition should be
1123
- * while (shift >= 0 && !isUnsignedSafeDouble(remHi))
1124
- * but we manually inline isUnsignedSafeDouble because remHi is a var. If
1125
- * we let the optimizer inline it, it will first store remHi in a temporary
1126
- * val, which will explose the while condition as a while(true) + if +
1127
- * break, and we don't want that.
1128
- */
1129
- while (shift>= 0 && (remHi& UnsignedSafeDoubleHiMask )!= 0 ) {
1130
- if (inlineUnsigned_>= (remLo, remHi, bShiftLo, bShiftHi)) {
1131
- val newRem =
1132
- new RuntimeLong (remLo, remHi)- new RuntimeLong (bShiftLo, bShiftHi)
1133
- remLo= newRem.lo
1134
- remHi= newRem.hi
1135
- if (shift< 32 )
1136
- quotLo|= (1 << shift)
1137
- else
1138
- quotHi|= (1 << shift)// == (1 << (shift - 32))
1139
- }
1140
- shift-= 1
1141
- val newBShift = new RuntimeLong (bShiftLo, bShiftHi)>>> 1
1142
- bShiftLo= newBShift.lo
1143
- bShiftHi= newBShift.hi
1144
- }
1145
-
1146
- // Now rem < 2^53, we can finish with a double division
1147
- if (inlineUnsigned_>= (remLo, remHi, blo, bhi)) {
1148
- val remDouble = asUnsignedSafeDouble(remLo, remHi)
1149
- val bDouble = asUnsignedSafeDouble(blo, bhi)
979
+ if (bhi== 0 && inlineUnsignedInt_<(blo,1 << 21 )) {
980
+ // b < 2^21
1150
981
982
+ val quotHi = Integer .divideUnsigned(ahi, blo)// takes care of the division by zero check
983
+ val k = ahi- quotHi* blo// remainder of the above division; k < blo
984
+ // (alo, k) is exact because it uses at most 32 + 21 = 53 bits
985
+ val remainingNum = asUnsignedSafeDouble(alo, k)
1151
986
if (askQuotient) {
1152
- val rem_div_bDouble = fromUnsignedSafeDouble(remDouble/ bDouble)
1153
- val newQuot = new RuntimeLong (quotLo, quotHi)+ rem_div_bDouble
1154
- hiReturn= newQuot.hi
1155
- newQuot.lo
987
+ hiReturn= quotHi
988
+ rawToInt(remainingNum/ blo.toDouble)
1156
989
}else {
1157
- val rem_mod_bDouble = remDouble% bDouble
1158
- hiReturn= unsignedSafeDoubleHi(rem_mod_bDouble)
1159
- unsignedSafeDoubleLo(rem_mod_bDouble)
990
+ hiReturn= 0
991
+ rawToInt(remainingNum% blo.toDouble)
1160
992
}
1161
993
}else {
994
+ // b >= 2^21
995
+
996
+ val longNum = new RuntimeLong (alo, ahi)
997
+ val longDivisor = new RuntimeLong (blo, bhi)
998
+ val approxDivisor = unsignedToDoubleApprox(blo, bhi)
999
+ val approxNum = unsignedToDoubleApprox(alo, ahi)
1000
+ val approxQuot = fromUnsignedSafeDouble(approxNum/ approxDivisor)
1001
+ val approxRem = longNum- longDivisor* approxQuot
1002
+
1162
1003
if (askQuotient) {
1163
- hiReturn= quotHi
1164
- quotLo
1004
+ if (approxRem.hi< 0 ) {
1005
+ val result = approxQuot- new RuntimeLong (1 ,0 )
1006
+ hiReturn= result.hi
1007
+ result.lo
1008
+ }else if (geu(approxRem, longDivisor)) {
1009
+ val result = approxQuot+ new RuntimeLong (1 ,0 )
1010
+ hiReturn= result.hi
1011
+ result.lo
1012
+ }else {
1013
+ hiReturn= approxQuot.hi
1014
+ approxQuot.lo
1015
+ }
1165
1016
}else {
1166
- hiReturn= remHi
1167
- remLo
1017
+ if (approxRem.hi< 0 ) {
1018
+ val result = approxRem+ longDivisor
1019
+ hiReturn= result.hi
1020
+ result.lo
1021
+ }else if (geu(approxRem, longDivisor)) {
1022
+ val result = approxRem- longDivisor
1023
+ hiReturn= result.hi
1024
+ result.lo
1025
+ }else {
1026
+ hiReturn= approxRem.hi
1027
+ approxRem.lo
1028
+ }
1168
1029
}
1169
1030
}
1170
1031
}
@@ -1215,6 +1076,10 @@ object RuntimeLong {
1215
1076
@ inlinedef unsignedSafeDoubleHi (x :Double ): Int =
1216
1077
rawToInt(x/ TwoPow32 )
1217
1078
1079
+ /** Converts the unsigned long (lo, hi) to a Double, subject to rounding.*/
1080
+ @ inlinedef unsignedToDoubleApprox (lo :Int ,hi :Int ): Double =
1081
+ asUint(hi)* TwoPow32 + asUint(lo)
1082
+
1218
1083
/** Interprets an `Int` as an unsigned integer and returns its value as a
1219
1084
* `Double`.
1220
1085
*/