@@ -76,10 +76,9 @@ final class RuntimeLong(val lo: Int, val hi: Int) {
76
76
77
77
// A few operator-friendly methods used by the division algorithms
78
78
79
- @ inline private def << (b : Int ): RuntimeLong = RuntimeLong .shl(this , b)
80
- @ inline private def >>> (b : Int ): RuntimeLong = RuntimeLong .shr(this , b)
81
79
@ inline private def + (b : RuntimeLong ): RuntimeLong = RuntimeLong .add(this , b)
82
80
@ inline private def - (b : RuntimeLong ): RuntimeLong = RuntimeLong .sub(this , b)
81
+ @ inline private def * (b : RuntimeLong ): RuntimeLong = RuntimeLong .mul(this , b)
83
82
}
84
83
85
84
object RuntimeLong {
@@ -910,7 +909,7 @@ object RuntimeLong {
910
909
}
911
910
912
911
def divideImpl (alo : Int , ahi : Int , blo : Int , bhi : Int ): Int = {
913
- if (isZero (blo, bhi))
912
+ if (bothZero (blo, bhi))
914
913
throw new ArithmeticException (" / by zero" )
915
914
916
915
if (isInt32(alo, ahi)) {
@@ -950,7 +949,7 @@ object RuntimeLong {
950
949
}
951
950
952
951
def divideUnsignedImpl (alo : Int , ahi : Int , blo : Int , bhi : Int ): Int = {
953
- if (isZero (blo, bhi))
952
+ if (bothZero (blo, bhi))
954
953
throw new ArithmeticException (" / by zero" )
955
954
956
955
if (isUInt32(ahi)) {
@@ -968,7 +967,7 @@ object RuntimeLong {
968
967
}
969
968
970
969
private def unsigned_/ (alo : Int , ahi : Int , blo : Int , bhi : Int ): Int = {
971
- // This method is not called if isInt32(alo, ahi) nor if isZero (blo, bhi)
970
+ // This method is not called if isInt32(alo, ahi) nor if bothZero (blo, bhi)
972
971
if (isUnsignedSafeDouble(ahi)) {
973
972
if (isUnsignedSafeDouble(bhi)) {
974
973
val aDouble = asSafeDouble(alo, ahi)
@@ -1003,7 +1002,7 @@ object RuntimeLong {
1003
1002
}
1004
1003
1005
1004
def remainderImpl (alo : Int , ahi : Int , blo : Int , bhi : Int ): Int = {
1006
- if (isZero (blo, bhi))
1005
+ if (bothZero (blo, bhi))
1007
1006
throw new ArithmeticException (" / by zero" )
1008
1007
1009
1008
if (isInt32(alo, ahi)) {
@@ -1038,7 +1037,7 @@ object RuntimeLong {
1038
1037
}
1039
1038
1040
1039
def remainderUnsignedImpl (alo : Int , ahi : Int , blo : Int , bhi : Int ): Int = {
1041
- if (isZero (blo, bhi))
1040
+ if (bothZero (blo, bhi))
1042
1041
throw new ArithmeticException (" / by zero" )
1043
1042
1044
1043
if (isUInt32(ahi)) {
@@ -1056,7 +1055,7 @@ object RuntimeLong {
1056
1055
}
1057
1056
1058
1057
private def unsigned_% (alo : Int , ahi : Int , blo : Int , bhi : Int ): Int = {
1059
- // This method is not called if isInt32(alo, ahi) nor if isZero (blo, bhi)
1058
+ // This method is not called if isInt32(alo, ahi) nor if bothZero (blo, bhi)
1060
1059
if (isUnsignedSafeDouble(ahi)) {
1061
1060
if (isUnsignedSafeDouble(bhi)) {
1062
1061
val aDouble = asSafeDouble(alo, ahi)
@@ -1088,71 +1087,97 @@ object RuntimeLong {
1088
1087
* remainder. Stores the hi word of the result in `hiReturn`, and returns
1089
1088
* the lo word.
1090
1089
*/
1090
+ @ inline // inlined twice; specializes for askQuotient
1091
1091
private def unsignedDivModHelper (alo : Int , ahi : Int , blo : Int , bhi : Int ,
1092
1092
askQuotient : Boolean ): Int = {
1093
1093
1094
- var shift =
1095
- inlineNumberOfLeadingZeros(blo, bhi) - inlineNumberOfLeadingZeros(alo, ahi)
1096
- val initialBShift = new RuntimeLong (blo, bhi) << shift
1097
- var bShiftLo = initialBShift.lo
1098
- var bShiftHi = initialBShift.hi
1099
- var remLo = alo
1100
- var remHi = ahi
1101
- var quotLo = 0
1102
- var quotHi = 0
1103
-
1104
- /* Invariants:
1105
- * bShift == b << shift == b * 2^shift
1106
- * quot >= 0
1107
- * 0 <= rem < 2 * bShift
1108
- * quot * b + rem == a
1109
- *
1110
- * The loop condition should be
1111
- * while (shift >= 0 && !isUnsignedSafeDouble(remHi))
1112
- * but we manually inline isUnsignedSafeDouble because remHi is a var. If
1113
- * we let the optimizer inline it, it will first store remHi in a temporary
1114
- * val, which will explose the while condition as a while(true) + if +
1115
- * break, and we don't want that.
1116
- */
1117
- while (shift >= 0 && (remHi & SafeDoubleHiMask ) != 0 ) {
1118
- if (inlineUnsigned_>= (remLo, remHi, bShiftLo, bShiftHi)) {
1119
- val newRem =
1120
- new RuntimeLong (remLo, remHi) - new RuntimeLong (bShiftLo, bShiftHi)
1121
- remLo = newRem.lo
1122
- remHi = newRem.hi
1123
- if (shift < 32 )
1124
- quotLo |= (1 << shift)
1125
- else
1126
- quotHi |= (1 << shift) // == (1 << (shift - 32))
1094
+ // scalastyle:off return
1095
+
1096
+ val result = if (bothZero(bhi, blo & 0xffe00000 )) {
1097
+ // b < 2^21
1098
+
1099
+ val quotHi = Integer .divideUnsigned(ahi, blo) // takes care of the division by zero check
1100
+ val k = ahi - quotHi * blo // remainder of the above division; k < blo
1101
+ // (alo, k) is exact because it uses at most 32 + 21 = 53 bits
1102
+ val remainingNum = asSafeDouble(alo, k)
1103
+ if (askQuotient)
1104
+ new RuntimeLong (rawToInt(remainingNum / blo.toDouble), quotHi)
1105
+ else
1106
+ new RuntimeLong (rawToInt(remainingNum % blo.toDouble), 0 )
1107
+ } else if ((bhi & 0xc0000000 ) == 0 ) {
1108
+ // 2^21 <= b < 2^62
1109
+
1110
+ val longNum = new RuntimeLong (alo, ahi)
1111
+ val longDivisor = new RuntimeLong (blo, bhi)
1112
+ val approxDivisor = unsignedToDoubleApprox(blo, bhi)
1113
+ val approxNum = unsignedToDoubleApprox(alo, ahi)
1114
+ val approxQuot = fromUnsignedSafeDouble(approxNum / approxDivisor)
1115
+ val approxRem = longNum - longDivisor * approxQuot
1116
+
1117
+ if (approxRem.hi < 0 ) {
1118
+ if (askQuotient) approxQuot - new RuntimeLong (1 , 0 )
1119
+ else approxRem + longDivisor
1120
+ } else if (geu(approxRem, longDivisor)) {
1121
+ if (askQuotient) approxQuot + new RuntimeLong (1 , 0 )
1122
+ else approxRem - longDivisor
1123
+ } else {
1124
+ if (askQuotient) approxQuot
1125
+ else approxRem
1127
1126
}
1128
- shift -= 1
1129
- val newBShift = new RuntimeLong (bShiftLo, bShiftHi) >>> 1
1130
- bShiftLo = newBShift.lo
1131
- bShiftHi = newBShift.hi
1127
+ } else {
1128
+ // 2^62 <= b
1129
+ return unsignedDivModHugeDivisor(alo, ahi, blo, bhi, askQuotient)
1132
1130
}
1133
1131
1134
- // Now rem < 2^53, we can finish with a double division
1135
- if (inlineUnsigned_>= (remLo, remHi, blo, bhi)) {
1136
- val remDouble = asSafeDouble(remLo, remHi)
1137
- val bDouble = asSafeDouble(blo, bhi)
1132
+ hiReturn = result.hi
1133
+ result.lo
1134
+
1135
+ // scalastyle:on return
1136
+ }
1137
+
1138
+ private def unsignedDivModHugeDivisor (alo : Int , ahi : Int , blo : Int , bhi : Int ,
1139
+ askQuotient : Boolean ): Int = {
1140
+
1141
+ /* Called for b >= 2^62.
1142
+ * Such huge divisors are practically useless, but they defeat the
1143
+ * correction code of the fast algorithm above.
1144
+ * Since there are only 4 possible outcomes for the quotient, we perform
1145
+ * a "binary search" among those.
1146
+ */
1147
+
1148
+ val a = new RuntimeLong (alo, ahi)
1149
+ val b = new RuntimeLong (blo, bhi)
1138
1150
1139
- if (askQuotient) {
1140
- val rem_div_bDouble = fromUnsignedSafeDouble(remDouble / bDouble)
1141
- val newQuot = new RuntimeLong (quotLo, quotHi) + rem_div_bDouble
1142
- hiReturn = newQuot.hi
1143
- newQuot.lo
1151
+ var quot = 0
1152
+
1153
+ // Since b >= 2^62, we know that rem < 4*b (mathematically)
1154
+
1155
+ val rem1 = if (bhi >= 0 ) {
1156
+ // Bit 63 is 0: 2*b does not overflow, and we need a 4-way search
1157
+ val b2 = shl(b, 1 )
1158
+ if (geu(a, b2)) {
1159
+ quot = 2
1160
+ a - b2
1144
1161
} else {
1145
- val rem_mod_bDouble = remDouble % bDouble
1146
- hiReturn = unsignedSafeDoubleHi(rem_mod_bDouble)
1147
- unsignedSafeDoubleLo(rem_mod_bDouble)
1162
+ a
1148
1163
}
1149
1164
} else {
1150
- if (askQuotient) {
1151
- hiReturn = quotHi
1152
- quotLo
1165
+ a
1166
+ }
1167
+
1168
+ // Now rem < 2*b (mathematically)
1169
+ val rem1LTUb = ltu(rem1, b) // compute once for code size
1170
+ if (askQuotient) {
1171
+ hiReturn = 0
1172
+ if (rem1LTUb) quot else quot + 1
1173
+ } else {
1174
+ if (rem1LTUb) {
1175
+ hiReturn = rem1.hi
1176
+ rem1.lo
1153
1177
} else {
1154
- hiReturn = remHi
1155
- remLo
1178
+ val rem2 = rem1 - b
1179
+ hiReturn = rem2.hi
1180
+ rem2.lo
1156
1181
}
1157
1182
}
1158
1183
}
@@ -1163,9 +1188,9 @@ object RuntimeLong {
1163
1188
s.jsSubstring(start)
1164
1189
}
1165
1190
1166
- /** Tests whether the long (lo, hi) is 0 . */
1167
- @ inline def isZero ( lo : Int , hi : Int ): Boolean =
1168
- (lo | hi ) == 0
1191
+ /** Tests whether `a == 0 && b == 0` with a single comparison . */
1192
+ @ inline def bothZero ( a : Int , b : Int ): Boolean =
1193
+ (a | b ) == 0
1169
1194
1170
1195
/** Tests whether the long (lo, hi)'s mathematical value fits in a signed Int. */
1171
1196
@ inline def isInt32 (lo : Int , hi : Int ): Boolean =
@@ -1285,17 +1310,6 @@ object RuntimeLong {
1285
1310
@ inline def log2OfPowerOfTwo (i : Int ): Int =
1286
1311
31 - Integer .numberOfLeadingZeros(i)
1287
1312
1288
- /** Returns the number of leading zeros in the given long (lo, hi). */
1289
- @ inline def inlineNumberOfLeadingZeros (lo : Int , hi : Int ): Int =
1290
- if (hi != 0 ) Integer .numberOfLeadingZeros(hi)
1291
- else Integer .numberOfLeadingZeros(lo) + 32
1292
-
1293
- /** Tests whether the unsigned long (alo, ahi) is >= (blo, bhi). */
1294
- @ inline
1295
- def inlineUnsigned_>= (alo : Int , ahi : Int , blo : Int , bhi : Int ): Boolean =
1296
- if (ahi == bhi) inlineUnsignedInt_>= (alo, blo)
1297
- else inlineUnsignedInt_>= (ahi, bhi)
1298
-
1299
1313
@ inline
1300
1314
def inlineUnsignedInt_< (a : Int , b : Int ): Boolean =
1301
1315
(a ^ 0x80000000 ) < (b ^ 0x80000000 )
0 commit comments