Skip to content

Commit c753581

Browse files
committed
Add isnumeric function and base conversion corner case fix
1 parent 1cc791a commit c753581

File tree

4 files changed

+82
-21
lines changed

4 files changed

+82
-21
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ clean:
2121
rm -f *.out
2222

2323
install:
24-
luarocks make --local $(ROCKSPEC)
24+
luarocks make --local
2525

2626
upload:
2727
luarocks upload --api-key=$(LUAROCKS_APIKEY) $(ROCKSPEC)

bint.lua

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ local bint = {}
109109
bint.__index = bint
110110

111111
-- Constants used internally and modified by bint.scale
112+
local BIGINT_BITS
112113
local BIGINT_SIZE
113114
local BIGINT_WORDBITS
114115
local BIGINT_WORDMAX
@@ -137,6 +138,7 @@ function bint.scale(bits, wordbits)
137138
assert(bits % wordbits == 0, 'bitsize is not multiple of word bitsize')
138139
assert(2*wordbits <= luainteger_bitsize(), 'word bitsize must be half of the lua integer bitsize')
139140
assert(bits >= 64, 'bitsize must be >= 64')
141+
BIGINT_BITS = bits
140142
BIGINT_SIZE = bits // wordbits
141143
BIGINT_WORDBITS = wordbits
142144
BIGINT_WORDMAX = (1 << BIGINT_WORDBITS) - 1
@@ -388,7 +390,8 @@ end
388390
-- @param[opt] base Base to be represented, defaults to 10.
389391
-- Must be at least 2 and at most 36.
390392
-- @param[opt] unsigned Whether to output as unsigned integer.
391-
-- Defaults to true for base 10 and false for others.
393+
-- Defaults to false for base 10 and true for others.
394+
-- When unsigned is false the symbol '-' is prepended in negative values.
392395
-- @return A string representing the input.
393396
-- @raise An assert is thrown in case the base is invalid.
394397
function bint.tobase(x, base, unsigned)
@@ -402,22 +405,22 @@ function bint.tobase(x, base, unsigned)
402405
-- number base is too large
403406
return nil
404407
end
408+
if unsigned == nil then
409+
unsigned = base ~= 10
410+
end
405411
if base == 10 or base == 16 then
406412
local inluarange = x >= BIGINT_MATHMININTEGER and x <= BIGINT_MATHMAXINTEGER
407413
if inluarange then
408414
-- integer is small, use tostring or string.format (faster)
409415
local n = x:tointeger()
410416
if base == 10 then
411417
return tostring(n)
412-
else
418+
elseif unsigned then
413419
return string.format('%x', n)
414420
end
415421
end
416422
end
417423
local ss = {}
418-
if unsigned == nil then
419-
unsigned = base ~= 10
420-
end
421424
local neg = not unsigned and x:isneg()
422425
if neg then
423426
x = x:abs()
@@ -577,10 +580,16 @@ end
577580

578581
--- Check if the input is a lua integer or a bint.
579582
-- @param x Any lua value.
580-
function bint.isinteger(x)
583+
function bint.isintegral(x)
581584
return isbint(x) or math.type(x) == 'integer'
582585
end
583586

587+
--- Check if the input is a bint or a lua number.
588+
-- @param x Any lua value.
589+
function bint.isnumeric(x)
590+
return isbint(x) or type(x) == 'number'
591+
end
592+
584593
--- Check the number type of the input (bint, integer or float).
585594
-- @param x Any lua value.
586595
-- Returns "bint" for bints, "integer" fot lua integers,
@@ -819,10 +828,24 @@ function bint.ceil(x)
819828
end
820829
end
821830

822-
--- Truncate a lua number to a bint.
831+
-- Wrap around bits of an integer (discarding left bits) considering bints.
832+
-- @param x A bint or a lua integer.
833+
-- @param y Number of right bits to preserve.
834+
function bint.bwrap(x, y)
835+
x = bint_assert_convert(x)
836+
if y <= 0 then
837+
return bint.zero()
838+
elseif y < BIGINT_BITS then
839+
return x & (bint.one() << y):_dec()
840+
else
841+
return bint.new(x)
842+
end
843+
end
844+
845+
--- Truncate a number to a bint.
823846
-- Floats numbers are truncated, that is, the fractional port is discarded.
824-
-- @param x A value to initialize from convertible to a lua number.
825-
-- @return A new bint or nil in case the input cannot be represented by an integer.
847+
-- @param x A number to truncate.
848+
-- @return A new bint or nil in case the input does not fit in a bint or is not a number.
826849
function bint.trunc(x)
827850
if not isbint(x) then
828851
x = tonumber(x)

docs/index.html

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,14 @@ <h2><a href="#Functions">Functions</a></h2>
196196
<td class="summary">Check if the input is a bint.</td>
197197
</tr>
198198
<tr>
199-
<td class="name" nowrap><a href="#isinteger">isinteger (x)</a></td>
199+
<td class="name" nowrap><a href="#isintegral">isintegral (x)</a></td>
200200
<td class="summary">Check if the input is a lua integer or a bint.</td>
201201
</tr>
202202
<tr>
203+
<td class="name" nowrap><a href="#isnumeric">isnumeric (x)</a></td>
204+
<td class="summary">Check if the input is a bint or a lua number.</td>
205+
</tr>
206+
<tr>
203207
<td class="name" nowrap><a href="#type">type (x)</a></td>
204208
<td class="summary">Check the number type of the input (bint, integer or float).</td>
205209
</tr>
@@ -281,7 +285,7 @@ <h2><a href="#Functions">Functions</a></h2>
281285
</tr>
282286
<tr>
283287
<td class="name" nowrap><a href="#trunc">trunc (x)</a></td>
284-
<td class="summary">Truncate a lua number to a bint.</td>
288+
<td class="summary">Truncate a number to a bint.</td>
285289
</tr>
286290
<tr>
287291
<td class="name" nowrap><a href="#max">max (x, y)</a></td>
@@ -667,7 +671,8 @@ <h3>Parameters:</h3>
667671
</li>
668672
<li><span class="parameter">unsigned</span>
669673
Whether to output as unsigned integer.
670-
Defaults to true for base 10 and false for others.
674+
Defaults to false for base 10 and true for others.
675+
When unsigned is false the symbol '-' is prepended in negative values.
671676
(<em>optional</em>)
672677
</li>
673678
</ul>
@@ -868,8 +873,8 @@ <h3>Parameters:</h3>
868873

869874
</dd>
870875
<dt>
871-
<a name = "isinteger"></a>
872-
<strong>isinteger (x)</strong>
876+
<a name = "isintegral"></a>
877+
<strong>isintegral (x)</strong>
873878
</dt>
874879
<dd>
875880
Check if the input is a lua integer or a bint.
@@ -886,6 +891,26 @@ <h3>Parameters:</h3>
886891

887892

888893

894+
</dd>
895+
<dt>
896+
<a name = "isnumeric"></a>
897+
<strong>isnumeric (x)</strong>
898+
</dt>
899+
<dd>
900+
Check if the input is a bint or a lua number.
901+
902+
903+
<h3>Parameters:</h3>
904+
<ul>
905+
<li><span class="parameter">x</span>
906+
Any lua value.
907+
</li>
908+
</ul>
909+
910+
911+
912+
913+
889914
</dd>
890915
<dt>
891916
<a name = "type"></a>
@@ -1243,21 +1268,21 @@ <h3>Parameters:</h3>
12431268
<strong>trunc (x)</strong>
12441269
</dt>
12451270
<dd>
1246-
Truncate a lua number to a bint.
1271+
Truncate a number to a bint.
12471272
Floats numbers are truncated, that is, the fractional port is discarded.
12481273

12491274

12501275
<h3>Parameters:</h3>
12511276
<ul>
12521277
<li><span class="parameter">x</span>
1253-
A value to initialize from convertible to a lua number.
1278+
A number to truncate.
12541279
</li>
12551280
</ul>
12561281

12571282
<h3>Returns:</h3>
12581283
<ol>
12591284

1260-
A new bint or nil in case the input cannot be represented by an integer.
1285+
A new bint or nil in case the input does not fit in a bint or is not a number.
12611286
</ol>
12621287

12631288

@@ -2222,7 +2247,7 @@ <h3>See also:</h3>
22222247
</div> <!-- id="main" -->
22232248
<div id="about">
22242249
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
2225-
<i style="float:right;">Last updated 2020-07-09 09:15:25 </i>
2250+
<i style="float:right;">Last updated 2020-07-09 17:52:38 </i>
22262251
</div> <!-- id="about" -->
22272252
</div> <!-- id="container" -->
22282253
</body>

tests.lua

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,11 @@ local function test(bits)
7878

7979
assert(bint.isbint(1) == false)
8080
assert(bint.isbint(bint(1)) == true)
81-
assert(bint.isinteger(1) == true)
82-
assert(bint.isinteger(bint(1)) == true)
81+
assert(bint.isintegral(1) == true)
82+
assert(bint.isintegral(bint(1)) == true)
83+
assert(bint.isnumeric(1) == true)
84+
assert(bint.isnumeric(1.5) == true)
85+
assert(bint.isnumeric(bint(1)) == true)
8386
assert(bint.type(1) == 'integer')
8487
assert(bint.type(1.5) == 'float')
8588
assert(bint.type(bint(1)) == 'bint')
@@ -189,6 +192,12 @@ local function test(bits)
189192
assert_eq(bint.tobase(8, 7), '11')
190193
assert_eq(bint.tobase(1, 37), nil)
191194
assert_eq(bint.tobase(1.5, 10), nil)
195+
assert_eq(bint.tobase(0xff, 16, true), 'ff')
196+
assert_eq(bint.tobase(-0xff, 16, false), '-ff')
197+
if bits > 64 then
198+
assert_eq(bint.tobase(-1, 16, true), 'ffffffffffffffff')
199+
assert_eq(bint.tobase(-2, 16, true), 'fffffffffffffffe')
200+
end
192201

193202
test_ops(0)
194203
test_ops(1)
@@ -339,9 +348,13 @@ local function test(bits)
339348
local function test_shrone(x)
340349
assert_eq(bint(x):_shrone():tointeger(), x >> 1)
341350
end
351+
local function test_bwrap(x, y)
352+
assert_eq(bint.bwrap(x, y):tointeger(), x & ((1 << math.max(y, 0))-1))
353+
end
342354
local function test_ops(x, y)
343355
test_shl(x, y) test_shl(x, -y)
344356
test_shr(x, y) test_shr(x, -y)
357+
test_bwrap(x, y) test_bwrap(x, -y) test_bwrap(-x, y)
345358
test_shlone(x) test_shlone(y)
346359
test_shrone(x) test_shrone(y)
347360
end

0 commit comments

Comments
 (0)