@@ -61,8 +61,8 @@ Then when you need create a bint, you can use one of the following functions:
6161* @{bint.frominteger} (convert from lua integers, preserving the sign)
6262* @{bint.fromnumber} (convert from lua floats, truncating the fractional part)
6363* @{bint.frombase} (convert from arbitrary bases, like hexadecimal)
64- * @{bint.new} (convert from anything, asserts on invalid values )
65- * @{bint.convert} (convert form anything, returns nil on invalid values )
64+ * @{bint.new} (convert from anything, asserts on invalid integers )
65+ * @{bint.convert} (convert form anything, returns nil on invalid integers )
6666* @{bint.parse} (convert from anything, returns a lua number as fallback)
6767* @{bint.zero}
6868* @{bint.one}
@@ -77,13 +77,12 @@ When you are done computing and need to get the result,
7777get the output from one of the following functions:
7878
7979* @{bint.touinteger} (convert to a lua integer, wraps around as an unsigned integer)
80- * @{bint.tointeger} (convert to a lua integer, always preserving the sign)
80+ * @{bint.tointeger} (convert to a lua integer, wraps around, preserves the sign)
8181* @{bint.tonumber} (convert to lua float, losing precision)
8282* @{bint.tobase} (convert to a string in any base)
8383* @{bint.__tostring} (convert to a string in base 10)
8484
85- Note that outputting to a lua number will make the integer overflow and its value wraps around.
86- To output very large integer with no loss of precision you probably want to use @{bint.tobase}
85+ To output very large integer with no loss you probably want to use @{bint.tobase}
8786or call `tostring` to get a string representation.
8887
8988## Precautions
258257
259258-- Compute power with lua integers.
260259local function ipow (y , x , n )
261- if n == 0 then
262- return y
263- elseif n == 1 then
260+ if n == 1 then
264261 return y * x
265262 elseif n & 1 == 0 then -- even
266263 return ipow (y , x * x , n // 2 )
@@ -463,11 +460,11 @@ end
463460function bint .new (x )
464461 if isbint (x ) then
465462 -- return a clone
466- local n = {}
463+ local n = bint_newempty ()
467464 for i = 1 ,BIGINT_SIZE do
468465 n [i ] = x [i ]
469466 end
470- return setmetatable ( n , bint )
467+ return n
471468 else
472469 x = bint_fromvalue (x )
473470 end
@@ -563,6 +560,12 @@ function bint.isminusone(x)
563560 end
564561end
565562
563+ --- Check if the input is a bint.
564+ -- @param x Any lua value.
565+ function bint .isbint (x )
566+ return isbint (x )
567+ end
568+
566569--- Check if a number is negative considering bints.
567570-- Zero is guaranteed to never be negative for bints.
568571-- @param x A bint or a lua number.
@@ -604,31 +607,23 @@ function bint.isodd(x)
604607 end
605608end
606609
607- --- Assign a bint to zero (in-place).
608- function bint :_zero ()
609- for i = 1 ,BIGINT_SIZE do
610- self [i ] = 0
611- end
612- return self
613- end
614-
615610--- Create a new bint with 0 value.
616611function bint .zero ()
617- return bint_newempty ():_zero ()
618- end
619-
620- --- Assign a bint to 1 (in-place).
621- function bint :_one ()
622- self [1 ] = 1
623- for i = 2 ,BIGINT_SIZE do
624- self [i ] = 0
612+ local x = bint_newempty ()
613+ for i = 1 ,BIGINT_SIZE do
614+ x [i ] = 0
625615 end
626- return self
616+ return x
627617end
628618
629619--- Create a new bint with 1 value.
630620function bint .one ()
631- return bint_newempty ():_one ()
621+ local x = bint_newempty ()
622+ x [1 ] = 1
623+ for i = 2 ,BIGINT_SIZE do
624+ x [i ] = 0
625+ end
626+ return x
632627end
633628
634629--- Bitwise left shift a bint in one bit (in-place).
@@ -775,10 +770,17 @@ end
775770-- @param x A bint or a lua number to be added.
776771-- @param y A bint or a lua number to be added.
777772function bint .__add (x , y )
778- local ix = bint .convert (x , true )
773+ local ix = bint .convert (x )
779774 local iy = bint .convert (y )
780775 if ix and iy then
781- return ix :_add (iy )
776+ local z = bint_newempty ()
777+ local carry = 0
778+ for i = 1 ,BIGINT_SIZE do
779+ local tmp = ix [i ] + iy [i ] + carry
780+ carry = tmp > BIGINT_WORDMAX and 1 or 0
781+ z [i ] = tmp & BIGINT_WORDMAX
782+ end
783+ return z
782784 else
783785 return bint .tonumber (x ) + bint .tonumber (y )
784786 end
@@ -803,10 +805,18 @@ end
803805-- @param x A bint or a lua number to be subtract from.
804806-- @param y A bint or a lua number to subtract.
805807function bint .__sub (x , y )
806- local ix = bint .convert (x , true )
808+ local ix = bint .convert (x )
807809 local iy = bint .convert (y )
808810 if ix and iy then
809- return ix :_sub (iy )
811+ local z = bint_newempty ()
812+ local borrow = 0
813+ local wordmaxp1 = BIGINT_WORDMAX + 1
814+ for i = 1 ,BIGINT_SIZE do
815+ local res = (ix [i ] + wordmaxp1 ) - (iy [i ] + borrow )
816+ z [i ] = res & BIGINT_WORDMAX
817+ borrow = res <= BIGINT_WORDMAX and 1 or 0
818+ end
819+ return z
810820 else
811821 return bint .tonumber (x ) - bint .tonumber (y )
812822 end
@@ -873,19 +883,18 @@ end
873883-- @see bint.udiv
874884-- @see bint.umod
875885function bint .udivmod (x , y )
876- local dividend = bint .convert (x , true )
877- local divisor = bint .convert (y )
886+ local dividend = bint .new (x )
887+ local divisor = bint_assert_convert (y )
888+ local quot = bint .zero ()
878889 assert (not divisor :iszero (), ' attempt to divide by zero' )
879890 if dividend :ult (divisor ) then
880- return bint . zero () , dividend
891+ return quot , dividend
881892 end
882893 -- align leftmost digits in dividend and divisor
883894 local divisorlbit = findleftbit (divisor )
884895 local divdendlbit , size = findleftbit (dividend )
885896 local bit = divdendlbit - divisorlbit
886897 divisor = divisor << bit
887- -- set quotient to 0
888- local quot = bint .zero ()
889898 local wordmaxp1 = BIGINT_WORDMAX + 1
890899 local wordbitsm1 = BIGINT_WORDBITS - 1
891900 while bit >= 0 do
@@ -1202,7 +1211,11 @@ end
12021211-- @param x An integer to perform bitwise NOT.
12031212-- @raise Asserts in case inputs are not convertible to integers.
12041213function bint .__bnot (x )
1205- return bint .new (x ):_bnot ()
1214+ local y = bint_newempty ()
1215+ for i = 1 ,BIGINT_SIZE do
1216+ y [i ] = (~x [i ]) & BIGINT_WORDMAX
1217+ end
1218+ return y
12061219end
12071220
12081221--- Negate a bint (in-place). This apply effectively apply two's complements.
@@ -1213,7 +1226,7 @@ end
12131226--- Negate a bint. This apply effectively apply two's complements.
12141227-- @param x A bint to perform negation.
12151228function bint .__unm (x )
1216- return bint . new ( x ):_unm ()
1229+ return (~ x ):_inc ()
12171230end
12181231
12191232--- Check if bints are equal.
@@ -1232,13 +1245,7 @@ end
12321245-- @param x A bint or lua number to compare.
12331246-- @param y A bint or lua number to compare.
12341247function bint .eq (x , y )
1235- local ix = bint .convert (x )
1236- local iy = bint .convert (y )
1237- if ix and iy then
1238- return ix == iy
1239- else
1240- return x == y
1241- end
1248+ return bint .convert (x ) == bint .convert (y )
12421249end
12431250
12441251--- Compare if integer x is less than y considering bints (unsigned version).
@@ -1278,12 +1285,18 @@ end
12781285-- @param y Right value to compare, a bint or lua number.
12791286-- @see bint.ult
12801287function bint .__lt (x , y )
1281- local ix = bint .convert (x )
1282- local iy = bint .convert (y )
1288+ local ix , iy = bint .convert (x ), bint .convert (y )
12831289 if ix and iy then
1284- local xneg , yneg = ix :isneg (), iy :isneg ()
1290+ local xneg = ix [BIGINT_SIZE ] & BIGINT_WORDMSB ~= 0
1291+ local yneg = iy [BIGINT_SIZE ] & BIGINT_WORDMSB ~= 0
12851292 if xneg == yneg then
1286- return bint .ult (ix , iy )
1293+ for i = BIGINT_SIZE ,1 ,- 1 do
1294+ local a , b = ix [i ], iy [i ]
1295+ if a ~= b then
1296+ return a < b
1297+ end
1298+ end
1299+ return false
12871300 else
12881301 return xneg and not yneg
12891302 end
@@ -1297,12 +1310,18 @@ end
12971310-- @param y Right value to compare, a bint or lua number.
12981311-- @see bint.ule
12991312function bint .__le (x , y )
1300- local ix = bint .convert (x )
1301- local iy = bint .convert (y )
1313+ local ix , iy = bint .convert (x ), bint .convert (y )
13021314 if ix and iy then
1303- local xneg , yneg = ix :isneg (), iy :isneg ()
1315+ local xneg = ix [BIGINT_SIZE ] & BIGINT_WORDMSB ~= 0
1316+ local yneg = iy [BIGINT_SIZE ] & BIGINT_WORDMSB ~= 0
13041317 if xneg == yneg then
1305- return bint .ule (ix , iy )
1318+ for i = BIGINT_SIZE ,1 ,- 1 do
1319+ local a , b = ix [i ], iy [i ]
1320+ if a ~= b then
1321+ return a < b
1322+ end
1323+ end
1324+ return true
13061325 else
13071326 return xneg and not yneg
13081327 end
0 commit comments