394
394
end
395
395
end
396
396
397
- -- Get the quotient and remainder for base digits
398
- local function xremainder ( dividend , divisor )
399
- local quo = bint_newempty ()
400
- local rem
397
+ -- Single word division modulus
398
+ local function sudivmod ( nume , deno )
399
+ local quot = bint_newempty ()
400
+ local rema
401
401
local carry = 0
402
402
for i = BINT_SIZE ,1 ,- 1 do
403
- carry = carry | dividend [i ]
404
- quo [i ] = carry // divisor
405
- rem = carry % divisor
406
- carry = rem << BINT_WORDBITS
403
+ carry = carry | nume [i ]
404
+ quot [i ] = carry // deno
405
+ rema = carry % deno
406
+ carry = rema << BINT_WORDBITS
407
407
end
408
- return quo , rem
408
+ return quot , rema
409
409
end
410
410
411
411
--- Convert a bint to a string in the desired base.
@@ -462,7 +462,7 @@ function bint.tobase(x, base, unsigned)
462
462
-- spit out base digits
463
463
while not stop do
464
464
local xd
465
- x , xd = xremainder (x , basepow )
465
+ x , xd = sudivmod (x , basepow )
466
466
stop = x :iszero ()
467
467
for _ = 1 ,step do
468
468
local d
@@ -1073,67 +1073,87 @@ end
1073
1073
-- @see bint.udiv
1074
1074
-- @see bint.umod
1075
1075
function bint .udivmod (x , y )
1076
- local dividend = bint .new (x )
1077
- local divisor = bint_assert_convert (y )
1078
- local quo = bint .zero ()
1079
- assert (not divisor :iszero (), ' attempt to divide by zero' )
1080
- if divisor :isone () then
1081
- return dividend , bint .zero ()
1082
- elseif dividend :ult (divisor ) then
1083
- return quo , dividend
1084
- end
1085
- -- align leftmost digits in dividend and divisor
1086
- local divisorlbit = findleftbit (divisor )
1087
- local divdendlbit , divdendsize = findleftbit (dividend )
1088
- local bit = divdendlbit - divisorlbit
1089
- divisor = divisor << bit
1076
+ local nume = bint .new (x )
1077
+ local deno = bint_assert_convert (y )
1078
+ -- compute if high bits of denominator are all zeros
1079
+ local ishighzero = true
1080
+ for i = BINT_SIZE ,2 ,- 1 do
1081
+ if deno [i ] ~= 0 then
1082
+ ishighzero = false
1083
+ break
1084
+ end
1085
+ end
1086
+ if ishighzero then
1087
+ -- try to divide by a single word (optimization)
1088
+ local low = deno [1 ]
1089
+ assert (low ~= 0 , ' attempt to divide by zero' )
1090
+ if low == 1 then
1091
+ -- denominator is one
1092
+ return nume , bint .zero ()
1093
+ elseif low <= (BINT_WORDMSB - 1 ) then
1094
+ -- can do single word division
1095
+ local rema
1096
+ nume , rema = sudivmod (nume , low )
1097
+ return nume , bint .new (rema )
1098
+ end
1099
+ end
1100
+ if nume :ult (deno ) then
1101
+ -- denominator is greater than denominator
1102
+ return bint .zero (), nume
1103
+ end
1104
+ -- align leftmost digits in numerator and denominator
1105
+ local denolbit = findleftbit (deno )
1106
+ local numelbit , numesize = findleftbit (nume )
1107
+ local bit = numelbit - denolbit
1108
+ deno = deno << bit
1090
1109
local wordmaxp1 = BINT_WORDMAX + 1
1091
1110
local wordbitsm1 = BINT_WORDBITS - 1
1092
- local divisorsize = divdendsize
1111
+ local denosize = numesize
1112
+ local quot = bint .zero ()
1093
1113
while bit >= 0 do
1094
- -- compute divisor <= dividend
1114
+ -- compute denominator <= numerator
1095
1115
local le = true
1096
- local size = math.max (divdendsize , divisorsize )
1116
+ local size = math.max (numesize , denosize )
1097
1117
for i = size ,1 ,- 1 do
1098
- local a , b = divisor [i ], dividend [i ]
1118
+ local a , b = deno [i ], nume [i ]
1099
1119
if a ~= b then
1100
1120
le = a < b
1101
1121
break
1102
1122
end
1103
1123
end
1104
- -- if the portion of the dividend above the divisor is greater or equal than to the divisor
1124
+ -- if the portion of the numerator above the denominator is greater or equal than to the denominator
1105
1125
if le then
1106
- -- subtract divisor from the portion of the dividend
1126
+ -- subtract denominator from the portion of the numerator
1107
1127
local borrow = 0
1108
1128
for i = 1 ,size do
1109
- local res = (dividend [i ] + wordmaxp1 ) - (divisor [i ] + borrow )
1110
- dividend [i ] = res & BINT_WORDMAX
1129
+ local res = (nume [i ] + wordmaxp1 ) - (deno [i ] + borrow )
1130
+ nume [i ] = res & BINT_WORDMAX
1111
1131
borrow = res <= BINT_WORDMAX and 1 or 0
1112
1132
end
1113
1133
-- concatenate 1 to the right bit of the quotient
1114
1134
local i = (bit // BINT_WORDBITS ) + 1
1115
- quo [i ] = quo [i ] | (1 << (bit % BINT_WORDBITS ))
1135
+ quot [i ] = quot [i ] | (1 << (bit % BINT_WORDBITS ))
1116
1136
end
1117
- -- shift right the divisor in one bit
1118
- for i = 1 ,divisorsize - 1 do
1119
- divisor [i ] = ((divisor [i ] >> 1 ) | (divisor [i + 1 ] << wordbitsm1 )) & BINT_WORDMAX
1137
+ -- shift right the denominator in one bit
1138
+ for i = 1 ,denosize - 1 do
1139
+ deno [i ] = ((deno [i ] >> 1 ) | (deno [i + 1 ] << wordbitsm1 )) & BINT_WORDMAX
1120
1140
end
1121
- local lastdivisorword = divisor [ divisorsize ] >> 1
1122
- divisor [ divisorsize ] = lastdivisorword
1123
- -- recalculate divisor size (optimization)
1124
- if lastdivisorword == 0 then
1125
- while divisor [ divisorsize ] == 0 do
1126
- divisorsize = divisorsize - 1
1141
+ local lastdenoword = deno [ denosize ] >> 1
1142
+ deno [ denosize ] = lastdenoword
1143
+ -- recalculate denominator size (optimization)
1144
+ if lastdenoword == 0 then
1145
+ while deno [ denosize ] == 0 do
1146
+ denosize = denosize - 1
1127
1147
end
1128
- if divisorsize == 0 then
1148
+ if denosize == 0 then
1129
1149
break
1130
1150
end
1131
1151
end
1132
1152
-- decrement current set bit for the quotient
1133
1153
bit = bit - 1
1134
1154
end
1135
- -- the remaining dividend is the remainder
1136
- return quo , dividend
1155
+ -- the remaining numerator is the remainder
1156
+ return quot , nume
1137
1157
end
1138
1158
1139
1159
--- Perform unsigned division between two integers considering bints.
@@ -1153,8 +1173,8 @@ end
1153
1173
-- @raise Asserts on attempt to divide by zero
1154
1174
-- or if the inputs are not convertible to integers.
1155
1175
function bint .umod (x , y )
1156
- local _ , rem = bint .udivmod (x , y )
1157
- return rem
1176
+ local _ , rema = bint .udivmod (x , y )
1177
+ return rema
1158
1178
end
1159
1179
1160
1180
--- Perform integer floor division and modulo operation between two numbers considering bints.
@@ -1171,25 +1191,25 @@ function bint.idivmod(x, y)
1171
1191
if iy :isminusone () then
1172
1192
return - ix , bint .zero ()
1173
1193
end
1174
- local quo , rem = bint .udivmod (ix :abs (), iy :abs ())
1194
+ local quot , rema = bint .udivmod (ix :abs (), iy :abs ())
1175
1195
local isnumneg , isdenomneg = ix :isneg (), iy :isneg ()
1176
1196
if isnumneg ~= isdenomneg then
1177
- quo :_unm ()
1197
+ quot :_unm ()
1178
1198
-- round quotient towards minus infinity
1179
- if not rem :iszero () then
1180
- quo :_dec ()
1199
+ if not rema :iszero () then
1200
+ quot :_dec ()
1181
1201
-- adjust the remainder
1182
1202
if isnumneg and not isdenomneg then
1183
- rem :_unm ():_add (y )
1203
+ rema :_unm ():_add (y )
1184
1204
elseif isdenomneg and not isnumneg then
1185
- rem :_add (y )
1205
+ rema :_add (y )
1186
1206
end
1187
1207
end
1188
1208
elseif isnumneg then
1189
1209
-- adjust the remainder
1190
- rem :_unm ()
1210
+ rema :_unm ()
1191
1211
end
1192
- return quo , rem
1212
+ return quot , rema
1193
1213
else
1194
1214
local nx , ny = bint .tonumber (x ), bint .tonumber (y )
1195
1215
return nx // ny , nx % ny
@@ -1204,7 +1224,23 @@ end
1204
1224
-- @return The quotient, a bint or lua number.
1205
1225
-- @raise Asserts on attempt to divide by zero.
1206
1226
function bint .__idiv (x , y )
1207
- return (bint .idivmod (x , y ))
1227
+ local ix , iy = bint .tobint (x ), bint .tobint (y )
1228
+ if ix and iy then
1229
+ if iy :isminusone () then
1230
+ return - ix , bint .zero ()
1231
+ end
1232
+ local quot , rema = bint .udivmod (ix :abs (), iy :abs ())
1233
+ if ix :isneg () ~= iy :isneg () then
1234
+ quot :_unm ()
1235
+ -- round quotient towards minus infinity
1236
+ if not rema :iszero () then
1237
+ quot :_dec ()
1238
+ end
1239
+ end
1240
+ return quot , rema
1241
+ else
1242
+ return bint .tonumber (x ) // bint .tonumber (y )
1243
+ end
1208
1244
end
1209
1245
1210
1246
--- Perform division between two numbers considering bints.
@@ -1224,8 +1260,8 @@ end
1224
1260
-- @return The remainder, a bint or lua number.
1225
1261
-- @raise Asserts on attempt to divide by zero.
1226
1262
function bint .__mod (x , y )
1227
- local _ , rem = bint .idivmod (x , y )
1228
- return rem
1263
+ local _ , rema = bint .idivmod (x , y )
1264
+ return rema
1229
1265
end
1230
1266
1231
1267
--- Perform integer power between two integers considering bints.
0 commit comments