@@ -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 {
@@ -1094,73 +1093,45 @@ object RuntimeLong {
1094
1093
* remainder. Stores the hi word of the result in `hiReturn`, and returns
1095
1094
* the lo word.
1096
1095
*/
1096
+ @ inline // inlined twice; specializes for askQuotient
1097
1097
private def unsignedDivModHelper (alo : Int , ahi : Int , blo : Int , bhi : Int ,
1098
1098
askQuotient : Boolean ): Int = {
1099
1099
1100
- var shift =
1101
- inlineNumberOfLeadingZeros(blo, bhi) - inlineNumberOfLeadingZeros(alo, ahi)
1102
- val initialBShift = new RuntimeLong (blo, bhi) << shift
1103
- var bShiftLo = initialBShift.lo
1104
- var bShiftHi = initialBShift.hi
1105
- var remLo = alo
1106
- var remHi = ahi
1107
- var quotLo = 0
1108
- var quotHi = 0
1109
-
1110
- /* Invariants:
1111
- * bShift == b << shift == b * 2^shift
1112
- * quot >= 0
1113
- * 0 <= rem < 2 * bShift
1114
- * quot * b + rem == a
1115
- *
1116
- * The loop condition should be
1117
- * while (shift >= 0 && !isUnsignedSafeDouble(remHi))
1118
- * but we manually inline isUnsignedSafeDouble because remHi is a var. If
1119
- * we let the optimizer inline it, it will first store remHi in a temporary
1120
- * val, which will explose the while condition as a while(true) + if +
1121
- * break, and we don't want that.
1122
- */
1123
- while (shift >= 0 && (remHi & SafeDoubleHiMask ) != 0 ) {
1124
- if (inlineUnsigned_>= (remLo, remHi, bShiftLo, bShiftHi)) {
1125
- val newRem =
1126
- new RuntimeLong (remLo, remHi) - new RuntimeLong (bShiftLo, bShiftHi)
1127
- remLo = newRem.lo
1128
- remHi = newRem.hi
1129
- if (shift < 32 )
1130
- quotLo |= (1 << shift)
1131
- else
1132
- quotHi |= (1 << shift) // == (1 << (shift - 32))
1133
- }
1134
- shift -= 1
1135
- val newBShift = new RuntimeLong (bShiftLo, bShiftHi) >>> 1
1136
- bShiftLo = newBShift.lo
1137
- bShiftHi = newBShift.hi
1138
- }
1139
-
1140
- // Now rem < 2^53, we can finish with a double division
1141
- if (inlineUnsigned_>= (remLo, remHi, blo, bhi)) {
1142
- val remDouble = asSafeDouble(remLo, remHi)
1143
- val bDouble = asSafeDouble(blo, bhi)
1144
-
1145
- if (askQuotient) {
1146
- val rem_div_bDouble = fromUnsignedSafeDouble(remDouble / bDouble)
1147
- val newQuot = new RuntimeLong (quotLo, quotHi) + rem_div_bDouble
1148
- hiReturn = newQuot.hi
1149
- newQuot.lo
1150
- } else {
1151
- val rem_mod_bDouble = remDouble % bDouble
1152
- hiReturn = unsignedSafeDoubleHi(rem_mod_bDouble)
1153
- unsignedSafeDoubleLo(rem_mod_bDouble)
1154
- }
1100
+ val result = if (bhi == 0 && inlineUnsignedInt_<(blo, 1 << 21 )) {
1101
+ // b < 2^21
1102
+
1103
+ val quotHi = Integer .divideUnsigned(ahi, blo) // takes care of the division by zero check
1104
+ val k = ahi - quotHi * blo // remainder of the above division; k < blo
1105
+ // (alo, k) is exact because it uses at most 32 + 21 = 53 bits
1106
+ val remainingNum = asSafeDouble(alo, k)
1107
+ if (askQuotient)
1108
+ new RuntimeLong (rawToInt(remainingNum / blo.toDouble), quotHi)
1109
+ else
1110
+ new RuntimeLong (rawToInt(remainingNum % blo.toDouble), 0 )
1155
1111
} else {
1156
- if (askQuotient) {
1157
- hiReturn = quotHi
1158
- quotLo
1112
+ // b >= 2^21
1113
+
1114
+ val longNum = new RuntimeLong (alo, ahi)
1115
+ val longDivisor = new RuntimeLong (blo, bhi)
1116
+ val approxDivisor = unsignedToDoubleApprox(blo, bhi)
1117
+ val approxNum = unsignedToDoubleApprox(alo, ahi)
1118
+ val approxQuot = fromUnsignedSafeDouble(approxNum / approxDivisor)
1119
+ val approxRem = longNum - longDivisor * approxQuot
1120
+
1121
+ if (approxRem.hi < 0 ) {
1122
+ if (askQuotient) approxQuot - new RuntimeLong (1 , 0 )
1123
+ else approxRem + longDivisor
1124
+ } else if (geu(approxRem, longDivisor)) {
1125
+ if (askQuotient) approxQuot + new RuntimeLong (1 , 0 )
1126
+ else approxRem - longDivisor
1159
1127
} else {
1160
- hiReturn = remHi
1161
- remLo
1128
+ if (askQuotient) approxQuot
1129
+ else approxRem
1162
1130
}
1163
1131
}
1132
+
1133
+ hiReturn = result.hi
1134
+ result.lo
1164
1135
}
1165
1136
1166
1137
@ inline
@@ -1291,17 +1262,6 @@ object RuntimeLong {
1291
1262
@ inline def log2OfPowerOfTwo (i : Int ): Int =
1292
1263
31 - Integer .numberOfLeadingZeros(i)
1293
1264
1294
- /** Returns the number of leading zeros in the given long (lo, hi). */
1295
- @ inline def inlineNumberOfLeadingZeros (lo : Int , hi : Int ): Int =
1296
- if (hi != 0 ) Integer .numberOfLeadingZeros(hi)
1297
- else Integer .numberOfLeadingZeros(lo) + 32
1298
-
1299
- /** Tests whether the unsigned long (alo, ahi) is >= (blo, bhi). */
1300
- @ inline
1301
- def inlineUnsigned_>= (alo : Int , ahi : Int , blo : Int , bhi : Int ): Boolean =
1302
- if (ahi == bhi) inlineUnsignedInt_>= (alo, blo)
1303
- else inlineUnsignedInt_>= (ahi, bhi)
1304
-
1305
1265
@ inline
1306
1266
def inlineUnsignedInt_< (a : Int , b : Int ): Boolean =
1307
1267
(a ^ 0x80000000 ) < (b ^ 0x80000000 )
0 commit comments