394394 end
395395end
396396
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
401401 local carry = 0
402402 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
407407 end
408- return quo , rem
408+ return quot , rema
409409end
410410
411411--- Convert a bint to a string in the desired base.
@@ -462,7 +462,7 @@ function bint.tobase(x, base, unsigned)
462462 -- spit out base digits
463463 while not stop do
464464 local xd
465- x , xd = xremainder (x , basepow )
465+ x , xd = sudivmod (x , basepow )
466466 stop = x :iszero ()
467467 for _ = 1 ,step do
468468 local d
@@ -1073,67 +1073,87 @@ end
10731073-- @see bint.udiv
10741074-- @see bint.umod
10751075function 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
10901109 local wordmaxp1 = BINT_WORDMAX + 1
10911110 local wordbitsm1 = BINT_WORDBITS - 1
1092- local divisorsize = divdendsize
1111+ local denosize = numesize
1112+ local quot = bint .zero ()
10931113 while bit >= 0 do
1094- -- compute divisor <= dividend
1114+ -- compute denominator <= numerator
10951115 local le = true
1096- local size = math.max (divdendsize , divisorsize )
1116+ local size = math.max (numesize , denosize )
10971117 for i = size ,1 ,- 1 do
1098- local a , b = divisor [i ], dividend [i ]
1118+ local a , b = deno [i ], nume [i ]
10991119 if a ~= b then
11001120 le = a < b
11011121 break
11021122 end
11031123 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
11051125 if le then
1106- -- subtract divisor from the portion of the dividend
1126+ -- subtract denominator from the portion of the numerator
11071127 local borrow = 0
11081128 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
11111131 borrow = res <= BINT_WORDMAX and 1 or 0
11121132 end
11131133 -- concatenate 1 to the right bit of the quotient
11141134 local i = (bit // BINT_WORDBITS ) + 1
1115- quo [i ] = quo [i ] | (1 << (bit % BINT_WORDBITS ))
1135+ quot [i ] = quot [i ] | (1 << (bit % BINT_WORDBITS ))
11161136 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
11201140 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
11271147 end
1128- if divisorsize == 0 then
1148+ if denosize == 0 then
11291149 break
11301150 end
11311151 end
11321152 -- decrement current set bit for the quotient
11331153 bit = bit - 1
11341154 end
1135- -- the remaining dividend is the remainder
1136- return quo , dividend
1155+ -- the remaining numerator is the remainder
1156+ return quot , nume
11371157end
11381158
11391159--- Perform unsigned division between two integers considering bints.
@@ -1153,8 +1173,8 @@ end
11531173-- @raise Asserts on attempt to divide by zero
11541174-- or if the inputs are not convertible to integers.
11551175function bint .umod (x , y )
1156- local _ , rem = bint .udivmod (x , y )
1157- return rem
1176+ local _ , rema = bint .udivmod (x , y )
1177+ return rema
11581178end
11591179
11601180--- Perform integer floor division and modulo operation between two numbers considering bints.
@@ -1171,25 +1191,25 @@ function bint.idivmod(x, y)
11711191 if iy :isminusone () then
11721192 return - ix , bint .zero ()
11731193 end
1174- local quo , rem = bint .udivmod (ix :abs (), iy :abs ())
1194+ local quot , rema = bint .udivmod (ix :abs (), iy :abs ())
11751195 local isnumneg , isdenomneg = ix :isneg (), iy :isneg ()
11761196 if isnumneg ~= isdenomneg then
1177- quo :_unm ()
1197+ quot :_unm ()
11781198 -- round quotient towards minus infinity
1179- if not rem :iszero () then
1180- quo :_dec ()
1199+ if not rema :iszero () then
1200+ quot :_dec ()
11811201 -- adjust the remainder
11821202 if isnumneg and not isdenomneg then
1183- rem :_unm ():_add (y )
1203+ rema :_unm ():_add (y )
11841204 elseif isdenomneg and not isnumneg then
1185- rem :_add (y )
1205+ rema :_add (y )
11861206 end
11871207 end
11881208 elseif isnumneg then
11891209 -- adjust the remainder
1190- rem :_unm ()
1210+ rema :_unm ()
11911211 end
1192- return quo , rem
1212+ return quot , rema
11931213 else
11941214 local nx , ny = bint .tonumber (x ), bint .tonumber (y )
11951215 return nx // ny , nx % ny
@@ -1204,7 +1224,23 @@ end
12041224-- @return The quotient, a bint or lua number.
12051225-- @raise Asserts on attempt to divide by zero.
12061226function 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
12081244end
12091245
12101246--- Perform division between two numbers considering bints.
@@ -1224,8 +1260,8 @@ end
12241260-- @return The remainder, a bint or lua number.
12251261-- @raise Asserts on attempt to divide by zero.
12261262function bint .__mod (x , y )
1227- local _ , rem = bint .idivmod (x , y )
1228- return rem
1263+ local _ , rema = bint .idivmod (x , y )
1264+ return rema
12291265end
12301266
12311267--- Perform integer power between two integers considering bints.
0 commit comments