shithub: mc

Download patch

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])
 }