ref: 6e35fce1673ee59c3bc1c302263ecb2e92fa5fe3
parent: d0c27d2dcc7ff982caadb7931e50e27e4ddc0c26
author: Ori Bernstein <[email protected]>
date: Fri Sep 12 14:37:14 EDT 2014
Improve bigint testing. Add test for big left shift, and add support for base when formatting bigints.
--- a/libstd/bigint.myr
+++ b/libstd/bigint.myr
@@ -25,8 +25,8 @@
const bigdup : (a : bigint# -> bigint#)
const bigassign : (d : bigint#, s : bigint# -> bigint#)
const bigparse : (s : byte[:] -> option(bigint#))
- const bigbfmt : (b : byte[:], a : bigint# -> size)
- const bigfmt : (a : bigint# -> byte[:])
+ const bigbfmt : (b : byte[:], a : bigint#, base : int -> size)
+ const bigfmt : (a : bigint#, base : int -> byte[:])
/*
const bigtoint : (a : bigint# -> @a::(numeric,integral))
*/
@@ -64,7 +64,7 @@
generic mkbigint = {v : @a::(integral,numeric)
var a
- var i
+ var val
a = zalloc()
@@ -74,10 +74,10 @@
elif v > 0
a.sign = 1
;;
- i = v castto(uint64)
- while i > 0
- a.dig = slpush(a.dig, (i castto(uint32)))
- i /= Base
+ val = v castto(uint64)
+ a.dig = slpush([][:], val castto(uint32))
+ if val > Base
+ a.dig = slpush(a.dig, (val/Base) castto(uint32))
;;
-> trim(a)
}
@@ -98,7 +98,7 @@
-> d
}
-const bigfmt = {a
+const bigfmt = {a, base
var buf
var n
@@ -111,19 +111,29 @@
or
2 + a.dig.len * 11
*/
- buf = slalloc(2 + a.dig.len * 11)
- n = bigbfmt(buf, a)
+ buf = slalloc(2 + a.dig.len * 13)
+ n = bigbfmt(buf, a, base)
-> buf[:n]
}
/* for now, just dump out something for debugging... */
-const bigbfmt = {buf, val
- const digitchars = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
+const bigbfmt = {buf, val, base
+ const digitchars = [
+ '0','1','2','3','4','5','6','7','8','9',
+ 'a','b','c','d','e','f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+ 't', 'u', 'v', 'w', 'x', 'y', 'z']
var v
var n, i
- var tmp
- var rem
+ var tmp, rem, b
+ if base < 0 || base > 36
+ die("invalid base in bigbfmt\n")
+ elif base == 0
+ b = mkbigint(10)
+ else
+ b = mkbigint(base)
+ ;;
n = 0
if val.sign == 0
n += encode(buf, '0')
@@ -134,7 +144,7 @@
val = bigdup(val)
/* generate the digits in reverse order */
while !bigiszero(val)
- (v, rem) = bigdivmod(val, mkbigint(10))
+ (v, rem) = bigdivmod(val, b)
if rem.dig.len > 0
n += bfmt(buf[n:], "%c", digitchars[rem.dig[0]])
else
@@ -145,7 +155,8 @@
val = v
;;
bigfree(val)
- /* we only generated ascii digits, so this works. ugh. */
+ bigfree(b)
+ /* we only generated ascii digits, so this works for reversing. */
for i = 0; i < n/2; i++
tmp = buf[i]
buf[i] = buf[n - i - 1]
@@ -604,6 +615,10 @@
off = s/32
shift = s % 32
+ /* zero shifted by anything is zero */
+ if a.sign == 0
+ -> a
+ ;;
a.dig = slzgrow(a.dig, 1 + a.dig.len + off castto(size))
/* blit over the base values */
for i = a.dig.len; i > off; i--
--- a/test/bigint.myr
+++ b/test/bigint.myr
@@ -2,7 +2,7 @@
const main = {
var a, b, c, d, e
- var buf : byte[1024], n
+ var buf : byte[4096], n
a = std.mkbigint(1234)
b = std.mkbigint(0x7fffffff)
@@ -21,7 +21,7 @@
std.bigfree(d)
std.bigfree(e)
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s\n", buf[:n])
/* smoke test */
@@ -34,16 +34,26 @@
| `std.None: std.die("Failed to parse b\n")
;;
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s / ", buf[:n])
- n = std.bigbfmt(buf[:], b)
+ n = std.bigbfmt(buf[:], b, 0)
std.put("%s == ", buf[:n])
std.bigdiv(a, b)
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s\n", buf[:n])
+ /* test big shifts */
+ a = std.mkbigint(1)
+ var shift = 4095
+ n = std.bigbfmt(buf[:], a, 0)
+ std.put("%s << %i == 0x", buf[:n], shift)
+ std.bigshli(a, shift)
+ n = std.bigbfmt(buf[:], a, 10)
+ std.put("%s\n", buf[:n])
+ std.put("top bits: %xi\n", a.dig[a.dig.len - 1])
+
/* no shifting */
match std.bigparse("0xffff_1234_1234_1234_1234")
| `std.Some val: a = val
@@ -54,14 +64,14 @@
| `std.None: std.die("Failed to parse b\n")
;;
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s / ", buf[:n])
- n = std.bigbfmt(buf[:], b)
+ n = std.bigbfmt(buf[:], b, 0)
std.put("%s == ", buf[:n])
std.bigdiv(a, b)
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s\n", buf[:n])
/* no shifting */
@@ -74,13 +84,13 @@
| `std.None: std.die("Failed to parse b\n")
;;
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s / ", buf[:n])
- n = std.bigbfmt(buf[:], b)
+ n = std.bigbfmt(buf[:], b, 0)
std.put("%s == ", buf[:n])
std.bigdiv(a, b)
- n = std.bigbfmt(buf[:], a)
+ n = std.bigbfmt(buf[:], a, 0)
std.put("%s\n", buf[:n])
}