Skip to content

Commit 5ce245a

Browse files
committed
Optimize frombase/tobase for small integers
1 parent 5c056d3 commit 5ce245a

File tree

4 files changed

+52
-24
lines changed

4 files changed

+52
-24
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ test:
66
lua examples/fibonacci.lua
77
lua examples/factorial.lua
88
lua examples/pi.lua
9+
lua examples/e.lua
910
lua examples/rsa.lua
1011

1112
docs:

bint.lua

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,27 +276,35 @@ function bint.frombase(s, base)
276276
if type(s) ~= 'string' then
277277
return nil
278278
end
279-
s = s:lower()
280279
base = base or 10
281280
if not (base >= 2 and base <= 36) then
282281
-- number base is too large
283282
return nil
284283
end
285-
local sign, int = s:match('^([+-]?)(%w+)$')
284+
local step = getbasestep(base)
285+
if #s < step then
286+
-- string is small, use tonumber (faster)
287+
return bint.frominteger(tonumber(s, base))
288+
end
289+
local sign, int = s:lower():match('^([+-]?)(%w+)$')
286290
if not (sign and int) then
287291
-- invalid integer string representation
288292
return nil
289293
end
290294
local n = bint.zero()
291-
local step = getbasestep(base)
292295
for i=1,#int,step do
293296
local part = int:sub(i,i+step-1)
294297
local d = tonumber(part, base)
295298
if not d then
296299
-- invalid integer string representation
297300
return nil
298301
end
299-
n = (n * ipow(1, base, #part)):_add(d)
302+
if i > 1 then
303+
n = n * ipow(1, base, #part)
304+
end
305+
if d ~= 0 then
306+
n:_add(d)
307+
end
300308
end
301309
if sign == '-' then
302310
n:_unm()
@@ -405,6 +413,18 @@ function bint.tobase(x, base, unsigned)
405413
-- number base is too large
406414
return nil
407415
end
416+
if base == 10 or base == 16 then
417+
local inluarange = x >= BIGINT_MATHMININTEGER and x <= BIGINT_MATHMAXINTEGER
418+
if inluarange then
419+
-- integer is small, use tostring or string.format (faster)
420+
local n = x:tointeger()
421+
if base == 10 then
422+
return tostring(n)
423+
else
424+
return string.format('%x', n)
425+
end
426+
end
427+
end
408428
local ss = {}
409429
if unsigned == nil then
410430
unsigned = base ~= 10

examples/bench.lua

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,31 @@ local function bench2(n, name, f, a, b)
2626
print(string.format('fact %8s %10.02fx', name, factor))
2727
end
2828

29-
bench2(100000, 'add', function(a, b) return a + b end, 1, 2)
30-
bench2(100000, 'sub', function(a, b) return a - b end, 1, 2)
31-
bench2(100000, 'mul', function(a, b) return a * b end, 1, 2)
29+
bench2(100000, 'add', function(a, b) return a + b end, 1, 2)
30+
bench2(100000, 'sub', function(a, b) return a - b end, 1, 2)
31+
bench2(100000, 'mul', function(a, b) return a * b end, 1, 2)
3232
bench2(30000, 'idiv', function(a, b) return a // b end, 1, 2)
33-
bench2(30000, 'mod', function(a, b) return a % b end, 1, 2)
34-
bench2(30000, 'div', function(a, b) return a / b end, 1, 2)
35-
bench2(100000, 'shl', function(a, b) return a << b end, 1, 2)
36-
bench2(100000, 'shr', function(a, b) return a >> b end, 1, 2)
33+
bench2(30000, 'mod', function(a, b) return a % b end, 1, 2)
34+
bench2(30000, 'div', function(a, b) return a / b end, 1, 2)
35+
bench2(100000, 'shl', function(a, b) return a << b end, 1, 2)
36+
bench2(100000, 'shr', function(a, b) return a >> b end, 1, 2)
3737
bench2(100000, 'band', function(a, b) return a & b end, 1, 2)
38-
bench2(100000, 'bor', function(a, b) return a | b end, 1, 2)
38+
bench2(100000, 'bor', function(a, b) return a | b end, 1, 2)
3939
bench2(100000, 'bxor', function(a, b) return a ~ b end, 1, 2)
4040
bench2(100000, 'bnot', function(a) return ~a end, 1)
41-
bench2(100000, 'unm', function(a) return -a end, 1)
42-
bench2(100000, 'eq', function(a, b) return a == b end, 1, 2)
43-
bench2(100000, 'lt', function(a, b) return a < b end, 1, 2)
44-
bench2(100000, 'le', function(a, b) return a <= b end, 1, 2)
45-
bench2(30000, 'pow', function(a, b) return a ^ b end, 1, 2)
46-
bench2(3000, 'tostring', function(a) return tostring(a) end, 1)
41+
bench2(100000, 'unm', function(a) return -a end, 1)
42+
bench2(100000, 'eq', function(a, b) return a == b end, 1, 2)
43+
bench2(100000, 'lt', function(a, b) return a < b end, 1, 2)
44+
bench2(100000, 'le', function(a, b) return a <= b end, 1, 2)
45+
bench2(30000, 'pow', function(a, b) return a ^ b end, 1, 2)
4746

48-
bench(100000, 'bint abs', function(a) return bint.abs(a) end, 1)
49-
bench(100000, 'bint dec', function(a) return bint.dec(a) end, 1)
50-
bench(100000, 'bint inc', function(a) return bint.inc(a) end, 1)
51-
bench(30000, 'bint ult', function(a, b) return bint.ult(a, b) end, 1, 2)
52-
bench(30000, 'bint ule', function(a, b) return bint.ule(a, b) end, 1, 2)
53-
bench(30000, 'bint ipow', function(a, b) return bint.ipow(a, b) end, 1, 2)
47+
bench(100000, 'bint abs', function(a) return bint.abs(a) end, 1)
48+
bench(100000, 'bint dec', function(a) return bint.dec(a) end, 1)
49+
bench(100000, 'bint inc', function(a) return bint.inc(a) end, 1)
50+
bench(30000, 'bint ult', function(a, b) return bint.ult(a, b) end, 1, 2)
51+
bench(30000, 'bint ule', function(a, b) return bint.ule(a, b) end, 1, 2)
52+
bench(30000, 'bint ipow', function(a, b) return bint.ipow(a, b) end, 1, 2)
53+
54+
bench(30000, 'luab tonumber', function(a) return tonumber(a) end, '2147483648')
55+
bench(30000, 'bint frombase', function(a) return bint.frombase(a) end, '2147483648')
56+
bench2(30000, 'tostring', function(a) return tostring(a) end, 1)

tests.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ local function test(bits)
7676
assert(bint(1) <= 1.5 == true)
7777
assert(bint.isbint(1) == false)
7878
assert(bint.isbint(bint(1)) == true)
79+
assert(tostring(bint.frombase('9223372036854775807')) == '9223372036854775807')
80+
assert(tostring(bint.frombase('-9223372036854775808')) == '-9223372036854775808')
81+
assert(bint.frombase('AAAAAAAAAAAAAAAAAAA') == nil)
82+
assert(bint.frombase('AAAAAAAAAAAAAAAAAAA_') == nil)
7983

8084
if bits > 96 then
8185
assert((bint(1) << 96):tonumber() > 1e28)

0 commit comments

Comments
 (0)