@@ -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
- @ inlineprivate def << (b :Int ): RuntimeLong = RuntimeLong .shl(this , b)
80
- @ inlineprivate def >>> (b :Int ): RuntimeLong = RuntimeLong .shr(this , b)
81
79
@ inlineprivate def + (b :RuntimeLong ): RuntimeLong = RuntimeLong .add(this , b)
82
80
@ inlineprivate def - (b :RuntimeLong ): RuntimeLong = RuntimeLong .sub(this , b)
81
+ @ inlineprivate def * (b :RuntimeLong ): RuntimeLong = RuntimeLong .mul(this , b)
83
82
}
84
83
85
84
object RuntimeLong {
@@ -916,37 +915,11 @@ object RuntimeLong {
916
915
}
917
916
918
917
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
- }
918
+ val aAbs = inline_abs(alo, ahi)
919
+ val bAbs = inline_abs(blo, bhi)
920
+ val absRLo = unsigned_/(aAbs.lo, aAbs.hi, bAbs.lo, bAbs.hi)
921
+ if ((ahi^ bhi)>= 0 ) absRLo// a and b have the same sign bit
922
+ else inline_negate_hiReturn(absRLo, hiReturn)
950
923
}
951
924
952
925
@ inline
@@ -955,52 +928,13 @@ object RuntimeLong {
955
928
new RuntimeLong (lo, hiReturn)
956
929
}
957
930
958
- def divideUnsignedImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int = {
959
- if (isZero(blo, bhi))
960
- throw new ArithmeticException (" / by zero" )
961
-
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
- }
931
+ @ inline
932
+ def divideUnsignedImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
933
+ unsigned_/(alo, ahi, blo, bhi)
975
934
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
- }
935
+ @ noinline
936
+ private def unsigned_/ (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
937
+ unsignedDivModHelper(alo, ahi, blo, bhi, askQuotient= true )
1004
938
1005
939
@ inline
1006
940
def remainder (a :RuntimeLong ,b :RuntimeLong ): RuntimeLong = {
@@ -1009,38 +943,11 @@ object RuntimeLong {
1009
943
}
1010
944
1011
945
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
- }
946
+ val aAbs = inline_abs(alo, ahi)
947
+ val bAbs = inline_abs(blo, bhi)
948
+ val absRLo = unsigned_%(aAbs.lo, aAbs.hi, bAbs.lo, bAbs.hi)
949
+ if (ahi< 0 ) inline_negate_hiReturn(absRLo, hiReturn)
950
+ else absRLo
1044
951
}
1045
952
1046
953
@ inline
@@ -1049,123 +956,61 @@ object RuntimeLong {
1049
956
new RuntimeLong (lo, hiReturn)
1050
957
}
1051
958
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
- }
959
+ @ inline
960
+ private def remainderUnsignedImpl (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
961
+ unsigned_%(alo, ahi, blo, bhi)
1069
962
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
- }
963
+ @ noinline
964
+ private def unsigned_% (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Int =
965
+ unsignedDivModHelper(alo, ahi, blo, bhi, askQuotient= false )
1096
966
1097
967
/** Helper for `unsigned_/` and `unsigned_%`.
1098
968
*
1099
969
* If `askQuotient` is true, computes the quotient, otherwise computes the
1100
970
* remainder. Stores the hi word of the result in `hiReturn`, and returns
1101
971
* the lo word.
1102
972
*/
973
+ @ inline
1103
974
private def unsignedDivModHelper (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ,
1104
975
askQuotient :Boolean ): Int = {
1105
976
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)
977
+ if (bhi== 0 && inlineUnsignedInt_<(blo,1 << 21 )) {
978
+ // b < 2^21
1150
979
980
+ val quotHi = Integer .divideUnsigned(ahi, blo)// takes care of the division by zero check
981
+ val k = ahi- quotHi* blo// remainder of the above division; k < blo
982
+ // (alo, k) is exact because it uses at most 32 + 21 = 53 bits
983
+ val remainingNum = asUnsignedSafeDouble(alo, k)
1151
984
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
985
+ hiReturn= quotHi
986
+ rawToInt(remainingNum/ blo.toDouble)
1156
987
}else {
1157
- val rem_mod_bDouble = remDouble% bDouble
1158
- hiReturn= unsignedSafeDoubleHi(rem_mod_bDouble)
1159
- unsignedSafeDoubleLo(rem_mod_bDouble)
988
+ hiReturn= 0
989
+ rawToInt(remainingNum% blo.toDouble)
1160
990
}
1161
991
}else {
1162
- if (askQuotient) {
1163
- hiReturn= quotHi
1164
- quotLo
992
+ // b >= 2^21
993
+
994
+ val longNum = new RuntimeLong (alo, ahi)
995
+ val longDivisor = new RuntimeLong (blo, bhi)
996
+ val approxDivisor = unsignedToDoubleApprox(blo, bhi)
997
+ val approxNum = unsignedToDoubleApprox(alo, ahi)
998
+ val approxQuot = fromUnsignedSafeDouble(approxNum/ approxDivisor)
999
+ val approxRem = longNum- longDivisor* approxQuot
1000
+
1001
+ val result = if (approxRem.hi< 0 ) {
1002
+ if (askQuotient) approxQuot- new RuntimeLong (1 ,0 )
1003
+ else approxRem+ longDivisor
1004
+ }else if (geu(approxRem, longDivisor)) {
1005
+ if (askQuotient) approxQuot+ new RuntimeLong (1 ,0 )
1006
+ else approxRem- longDivisor
1165
1007
}else {
1166
- hiReturn = remHi
1167
- remLo
1008
+ if (askQuotient) approxQuot
1009
+ else approxRem
1168
1010
}
1011
+
1012
+ hiReturn= result.hi
1013
+ result.lo
1169
1014
}
1170
1015
}
1171
1016
@@ -1175,18 +1020,10 @@ object RuntimeLong {
1175
1020
s.jsSubstring(start)
1176
1021
}
1177
1022
1178
- /** Tests whether the long (lo, hi) is 0.*/
1179
- @ inlinedef isZero (lo :Int ,hi :Int ): Boolean =
1180
- (lo| hi)== 0
1181
-
1182
1023
/** Tests whether the long (lo, hi)'s mathematical value fits in a signed Int.*/
1183
1024
@ inlinedef isInt32 (lo :Int ,hi :Int ): Boolean =
1184
1025
hi== (lo>> 31 )
1185
1026
1186
- /** Tests whether the long (_, hi)'s mathematical value fits in an unsigned Int.*/
1187
- @ inlinedef isUInt32 (hi :Int ): Boolean =
1188
- hi== 0
1189
-
1190
1027
/** Tests whether an unsigned long (lo, hi) is a safe Double.
1191
1028
* This test is in fact slightly stricter than necessary, as it tests
1192
1029
* whether `x < 2^53`, although x == 2^53 would be a perfectly safe
@@ -1215,6 +1052,10 @@ object RuntimeLong {
1215
1052
@ inlinedef unsignedSafeDoubleHi (x :Double ): Int =
1216
1053
rawToInt(x/ TwoPow32 )
1217
1054
1055
+ /** Converts the unsigned long (lo, hi) to a Double, subject to rounding.*/
1056
+ @ inlinedef unsignedToDoubleApprox (lo :Int ,hi :Int ): Double =
1057
+ asUint(hi)* TwoPow32 + asUint(lo)
1058
+
1218
1059
/** Interprets an `Int` as an unsigned integer and returns its value as a
1219
1060
* `Double`.
1220
1061
*/
@@ -1229,25 +1070,6 @@ object RuntimeLong {
1229
1070
(x| 0 ).asInstanceOf [Int ]
1230
1071
}
1231
1072
1232
- /** Tests whether the given non-zero unsigned Int is an exact power of 2.*/
1233
- @ inlinedef isPowerOfTwo_IKnowItsNot0 (i :Int ): Boolean =
1234
- (i& (i- 1 ))== 0
1235
-
1236
- /** Returns the log2 of the given unsigned Int assuming it is an exact power of 2.*/
1237
- @ inlinedef log2OfPowerOfTwo (i :Int ): Int =
1238
- 31 - Integer .numberOfLeadingZeros(i)
1239
-
1240
- /** Returns the number of leading zeros in the given long (lo, hi).*/
1241
- @ inlinedef inlineNumberOfLeadingZeros (lo :Int ,hi :Int ): Int =
1242
- if (hi!= 0 )Integer .numberOfLeadingZeros(hi)
1243
- else Integer .numberOfLeadingZeros(lo)+ 32
1244
-
1245
- /** Tests whether the unsigned long (alo, ahi) is >= (blo, bhi).*/
1246
- @ inline
1247
- def inlineUnsigned_>= (alo :Int ,ahi :Int ,blo :Int ,bhi :Int ): Boolean =
1248
- if (ahi== bhi) inlineUnsignedInt_>= (alo, blo)
1249
- else inlineUnsignedInt_>= (ahi, bhi)
1250
-
1251
1073
@ inline
1252
1074
def inlineUnsignedInt_< (a :Int ,b :Int ): Boolean =
1253
1075
(a^ 0x80000000 )< (b^ 0x80000000 )