math.big: implement decimal .str() for big numbers (#7314)
parent
f57c7032b4
commit
069d77d1c5
|
@ -1,61 +1,98 @@
|
||||||
module big
|
module big
|
||||||
|
|
||||||
// Wrapper for https://github.com/kokke/tiny-bignum-c
|
// Wrapper for https://github.com/kokke/tiny-bignum-c
|
||||||
|
|
||||||
#flag -I @VROOT/thirdparty/bignum
|
#flag -I @VROOT/thirdparty/bignum
|
||||||
#flag @VROOT/thirdparty/bignum/bn.o
|
#flag @VROOT/thirdparty/bignum/bn.o
|
||||||
#include "bn.h"
|
#include "bn.h"
|
||||||
|
|
||||||
[typedef]
|
[typedef]
|
||||||
struct C.bn {
|
struct C.bn {
|
||||||
array [32]u32
|
array [32]u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Big unsigned integer number.
|
||||||
type Number = C.bn
|
type Number = C.bn
|
||||||
|
|
||||||
fn C.bignum_init( n &Number )
|
fn C.bignum_init(n &Number)
|
||||||
fn C.bignum_from_int( n &Number, i u64 )
|
|
||||||
fn C.bignum_to_int( n &Number ) int
|
|
||||||
fn C.bignum_from_string( n &Number, s byteptr, nbytes int)
|
|
||||||
fn C.bignum_to_string( n &Number, s byteptr, maxsize int)
|
|
||||||
|
|
||||||
fn C.bignum_add( a &Number, b &Number, c &Number) // c = a + b
|
fn C.bignum_from_int(n &Number, i u64)
|
||||||
fn C.bignum_sub( a &Number, b &Number, c &Number) // c = a - b
|
|
||||||
fn C.bignum_mul( a &Number, b &Number, c &Number) // c = a * b
|
|
||||||
fn C.bignum_div( a &Number, b &Number, c &Number) // c = a / b
|
|
||||||
fn C.bignum_mod( a &Number, b &Number, c &Number) // c = a % b
|
|
||||||
fn C.bignum_divmod( a &Number, b &Number, c &Number, d &Number) // c = a/b d=a%b
|
|
||||||
|
|
||||||
fn C.bignum_and( a &Number, b &Number, c &Number) // c = a & b
|
fn C.bignum_to_int(n &Number) int
|
||||||
fn C.bignum_or( a &Number, b &Number, c &Number) // c = a | b
|
|
||||||
fn C.bignum_xor( a &Number, b &Number, c &Number) // c = a xor b
|
|
||||||
fn C.bignum_lshift( a &Number, b &Number, nbits int) // b = a << nbits
|
|
||||||
fn C.bignum_rshift( a &Number, b &Number, nbits int) // b = a >> nbits
|
|
||||||
|
|
||||||
fn C.bignum_cmp( a &Number, b &Number) int
|
fn C.bignum_from_string(n &Number, s byteptr, nbytes int)
|
||||||
fn C.bignum_is_zero( a &Number) int
|
|
||||||
|
fn C.bignum_to_string(n &Number, s byteptr, maxsize int)
|
||||||
|
|
||||||
|
// c = a + b
|
||||||
|
fn C.bignum_add(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a - b
|
||||||
|
fn C.bignum_sub(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a * b
|
||||||
|
fn C.bignum_mul(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a / b
|
||||||
|
fn C.bignum_div(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a % b
|
||||||
|
fn C.bignum_mod(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a/b d=a%b
|
||||||
|
fn C.bignum_divmod(a &Number, b &Number, c &Number, d &Number)
|
||||||
|
|
||||||
|
// c = a & b
|
||||||
|
fn C.bignum_and(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a | b
|
||||||
|
fn C.bignum_or(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// c = a xor b
|
||||||
|
fn C.bignum_xor(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// b = a << nbits
|
||||||
|
fn C.bignum_lshift(a &Number, b &Number, nbits int)
|
||||||
|
|
||||||
|
// b = a >> nbits
|
||||||
|
fn C.bignum_rshift(a &Number, b &Number, nbits int)
|
||||||
|
|
||||||
|
fn C.bignum_cmp(a &Number, b &Number) int
|
||||||
|
|
||||||
|
fn C.bignum_is_zero(a &Number) int
|
||||||
|
|
||||||
|
// n++
|
||||||
fn C.bignum_inc(n &Number)
|
fn C.bignum_inc(n &Number)
|
||||||
fn C.bignum_dec(n &Number)
|
|
||||||
fn C.bignum_pow( a &Number, b &Number, c &Number) // c = a ^ b
|
|
||||||
fn C.bignum_isqrt( a &Number, b &Number) // b = integer_square_root_of(a)
|
|
||||||
fn C.bignum_assign( dst &Number, src &Number) // copy src number to dst number
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
// n--
|
||||||
|
fn C.bignum_dec(n &Number)
|
||||||
|
|
||||||
|
// c = a ^ b
|
||||||
|
fn C.bignum_pow(a &Number, b &Number, c &Number)
|
||||||
|
|
||||||
|
// b = integer_square_root_of(a)
|
||||||
|
fn C.bignum_isqrt(a &Number, b &Number)
|
||||||
|
|
||||||
|
// copy src number to dst number
|
||||||
|
fn C.bignum_assign(dst &Number, src &Number)
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////
|
||||||
// conversion actions to/from big numbers:
|
// conversion actions to/from big numbers:
|
||||||
pub fn new() Number {
|
pub fn new() Number {
|
||||||
return Number{}
|
return Number{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_int(i int) Number {
|
pub fn from_int(i int) Number {
|
||||||
n := Number{}
|
n := Number{}
|
||||||
C.bignum_from_int( &n, i)
|
C.bignum_from_int(&n, i)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_u64(u u64) Number {
|
pub fn from_u64(u u64) Number {
|
||||||
n := Number{}
|
n := Number{}
|
||||||
C.bignum_from_int( &n, u)
|
C.bignum_from_int(&n, u)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts a hex string to big.Number.
|
||||||
pub fn from_string(s string) Number {
|
pub fn from_string(s string) Number {
|
||||||
n := Number{}
|
n := Number{}
|
||||||
C.bignum_from_string(&n, s.str, s.len)
|
C.bignum_from_string(&n, s.str, s.len)
|
||||||
|
@ -67,119 +104,147 @@ pub fn (n Number) int() int {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ten = from_int(10)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decimal representation for the big unsigned integer number n.
|
||||||
pub fn (n Number) str() string {
|
pub fn (n Number) str() string {
|
||||||
// TODO: return a decimal representation of the bignumber n.
|
if n.is_zero() {
|
||||||
// A decimal representation will be easier to use in the repl
|
return '0'
|
||||||
// but will be slower to calculate. Also, it is not implemented
|
}
|
||||||
// in the bn library.
|
mut digits := []byte{}
|
||||||
return 'Number (in hex): ' + n.hexstr()
|
mut x := n.clone()
|
||||||
|
div := Number{}
|
||||||
|
for !x.is_zero() {
|
||||||
|
mod := divmod(&x, &ten, &div)
|
||||||
|
digits << byte(mod.int()) + `0`
|
||||||
|
x = div
|
||||||
|
}
|
||||||
|
return digits.reverse().bytestr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (n Number) hexstr() string {
|
pub fn (n Number) hexstr() string {
|
||||||
mut buf := [8192]byte{}
|
mut buf := [8192]byte{}
|
||||||
C.bignum_to_string( &n, buf, 8192)
|
C.bignum_to_string(&n, buf, 8192)
|
||||||
// NB: bignum_to_string , returns the HEXADECIMAL representation of the bignum n
|
// NB: bignum_to_string , returns the HEXADECIMAL representation of the bignum n
|
||||||
s := tos_clone( buf )
|
s := tos_clone(buf)
|
||||||
if s.len == 0 { return '0' }
|
if s.len == 0 {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
// //////////////////////////////////////////////////////////
|
||||||
// overloaded ops for the numbers:
|
// overloaded ops for the numbers:
|
||||||
pub fn (a Number) + (b Number) Number {
|
pub fn (a Number) +(b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_add(&a, &b, &c)
|
C.bignum_add(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) - (b Number) Number {
|
pub fn (a Number) -(b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_sub(&a, &b, &c)
|
C.bignum_sub(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) * (b Number) Number {
|
pub fn (a Number) *(b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_mul(&a, &b, &c)
|
C.bignum_mul(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) / (b Number) Number {
|
pub fn (a Number) /(b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_div(&a, &b, &c)
|
C.bignum_div(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) % (b Number) Number {
|
pub fn (a Number) %(b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_mod(&a, &b, &c)
|
C.bignum_mod(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn divmod( a &Number, b &Number, c &Number) Number {
|
pub fn divmod(a &Number, b &Number, c &Number) Number {
|
||||||
d := Number{}
|
d := Number{}
|
||||||
C.bignum_divmod( a, b, c, &d)
|
C.bignum_divmod(a, b, c, &d)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
// //////////////////////////////////////////////////////////
|
||||||
pub fn cmp(a Number, b Number) int {
|
pub fn cmp(a Number, b Number) int {
|
||||||
return C.bignum_cmp(&a,&b)
|
return C.bignum_cmp(&a, &b)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) is_zero() bool {
|
pub fn (a Number) is_zero() bool {
|
||||||
return C.bignum_is_zero(&a) != 0
|
return C.bignum_is_zero(&a) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut a Number) inc() {
|
pub fn (mut a Number) inc() {
|
||||||
C.bignum_inc(a)
|
C.bignum_inc(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut a Number) dec() {
|
pub fn (mut a Number) dec() {
|
||||||
C.bignum_dec(a)
|
C.bignum_dec(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pow(a Number, b Number) Number {
|
pub fn pow(a Number, b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_pow(&a,&b,&c)
|
C.bignum_pow(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) isqrt() Number {
|
pub fn (a Number) isqrt() Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_isqrt(&a,&b)
|
C.bignum_isqrt(&a, &b)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
// //////////////////////////////////////////////////////////
|
||||||
pub fn b_and(a Number, b Number) Number {
|
pub fn b_and(a Number, b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_and(&a,&b,&c)
|
C.bignum_and(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b_or(a Number, b Number) Number {
|
pub fn b_or(a Number, b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_or(&a,&b,&c)
|
C.bignum_or(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b_xor(a Number, b Number) Number {
|
pub fn b_xor(a Number, b Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_xor(&a,&b,&c)
|
C.bignum_xor(&a, &b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) lshift(nbits int) Number {
|
pub fn (a Number) lshift(nbits int) Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_lshift(&a,&b,nbits)
|
C.bignum_lshift(&a, &b, nbits)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) rshift(nbits int) Number {
|
pub fn (a Number) rshift(nbits int) Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_rshift(&a,&b,nbits)
|
C.bignum_rshift(&a, &b, nbits)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) clone() Number {
|
pub fn (a Number) clone() Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_assign(&b,&a)
|
C.bignum_assign(&b, &a)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
// //////////////////////////////////////////////////////////
|
||||||
pub fn factorial(nn Number) Number {
|
pub fn factorial(nn Number) Number {
|
||||||
mut n := nn.clone()
|
mut n := nn.clone()
|
||||||
mut a := nn.clone()
|
mut a := nn.clone()
|
||||||
n.dec()
|
n.dec()
|
||||||
mut i:=1
|
mut i := 1
|
||||||
for !n.is_zero() {
|
for !n.is_zero() {
|
||||||
res := a * n
|
res := a * n
|
||||||
n.dec()
|
n.dec()
|
||||||
|
@ -190,5 +255,5 @@ pub fn factorial(nn Number) Number {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fact(n int) Number {
|
pub fn fact(n int) Number {
|
||||||
return factorial( from_int(n) )
|
return factorial(from_int(n))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import big
|
import big
|
||||||
|
|
||||||
fn test_new_big(){
|
fn test_new_big() {
|
||||||
n := big.new()
|
n := big.new()
|
||||||
assert sizeof( big.Number ) == 128
|
assert sizeof(big.Number) == 128
|
||||||
assert n.hexstr() == '0'
|
assert n.hexstr() == '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_from_int(){
|
fn test_from_int() {
|
||||||
assert big.from_int(255).hexstr() == 'ff'
|
assert big.from_int(255).hexstr() == 'ff'
|
||||||
assert big.from_int(127).hexstr() == '7f'
|
assert big.from_int(127).hexstr() == '7f'
|
||||||
assert big.from_int(1024).hexstr() == '400'
|
assert big.from_int(1024).hexstr() == '400'
|
||||||
|
@ -14,7 +14,7 @@ fn test_from_int(){
|
||||||
assert big.from_int(-1).hexstr() == 'ffffffffffffffff'
|
assert big.from_int(-1).hexstr() == 'ffffffffffffffff'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_from_u64(){
|
fn test_from_u64() {
|
||||||
assert big.from_u64(255).hexstr() == 'ff'
|
assert big.from_u64(255).hexstr() == 'ff'
|
||||||
assert big.from_u64(127).hexstr() == '7f'
|
assert big.from_u64(127).hexstr() == '7f'
|
||||||
assert big.from_u64(1024).hexstr() == '400'
|
assert big.from_u64(1024).hexstr() == '400'
|
||||||
|
@ -23,7 +23,7 @@ fn test_from_u64(){
|
||||||
assert big.from_u64(-1).hexstr() == 'ffffffffffffffff'
|
assert big.from_u64(-1).hexstr() == 'ffffffffffffffff'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_plus(){
|
fn test_plus() {
|
||||||
a := big.from_u64(2)
|
a := big.from_u64(2)
|
||||||
b := big.from_u64(3)
|
b := big.from_u64(3)
|
||||||
c := a + b
|
c := a + b
|
||||||
|
@ -31,7 +31,7 @@ fn test_plus(){
|
||||||
assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800'
|
assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_minus(){
|
fn test_minus() {
|
||||||
a := big.from_u64(2)
|
a := big.from_u64(2)
|
||||||
b := big.from_u64(3)
|
b := big.from_u64(3)
|
||||||
c := b - a
|
c := b - a
|
||||||
|
@ -41,20 +41,20 @@ fn test_minus(){
|
||||||
assert ee.hexstr() == '0'
|
assert ee.hexstr() == '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_divide(){
|
fn test_divide() {
|
||||||
a := big.from_u64(2)
|
a := big.from_u64(2)
|
||||||
b := big.from_u64(3)
|
b := big.from_u64(3)
|
||||||
c := b / a
|
c := b / a
|
||||||
assert c.hexstr() == '1'
|
assert c.hexstr() == '1'
|
||||||
assert (b % a ).hexstr() == '1'
|
assert (b % a).hexstr() == '1'
|
||||||
e := big.from_u64(1024) // dec(1024) == hex(0x400)
|
e := big.from_u64(1024) // dec(1024) == hex(0x400)
|
||||||
ee := e / e
|
ee := e / e
|
||||||
assert ee.hexstr() == '1'
|
assert ee.hexstr() == '1'
|
||||||
assert (e / a).hexstr() == '200'
|
assert (e / a).hexstr() == '200'
|
||||||
assert (e / (a*a)).hexstr() == '100'
|
assert (e / (a * a)).hexstr() == '100'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_multiply(){
|
fn test_multiply() {
|
||||||
a := big.from_u64(2)
|
a := big.from_u64(2)
|
||||||
b := big.from_u64(3)
|
b := big.from_u64(3)
|
||||||
c := b * a
|
c := b * a
|
||||||
|
@ -64,23 +64,35 @@ fn test_multiply(){
|
||||||
e4 := e2 * e2
|
e4 := e2 * e2
|
||||||
e8 := e2 * e2 * e2 * e2
|
e8 := e2 * e2 * e2 * e2
|
||||||
e9 := e8 + big.from_u64(1)
|
e9 := e8 + big.from_u64(1)
|
||||||
d := ((e9 * e9) + b) * c
|
d := ((e9 * e9) + b) * c
|
||||||
assert e4.hexstr() == '10000000000'
|
assert e4.hexstr() == '10000000000'
|
||||||
assert e8.hexstr() == '100000000000000000000'
|
assert e8.hexstr() == '100000000000000000000'
|
||||||
assert e9.hexstr() == '100000000000000000001'
|
assert e9.hexstr() == '100000000000000000001'
|
||||||
assert d.hexstr() == '60000000000000000000c00000000000000000018'
|
assert d.hexstr() == '60000000000000000000c00000000000000000018'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_mod(){
|
fn test_mod() {
|
||||||
assert (big.from_u64(13) % big.from_u64(10) ).int() == 3
|
assert (big.from_u64(13) % big.from_u64(10)).int() == 3
|
||||||
assert (big.from_u64(13) % big.from_u64(9) ).int() == 4
|
assert (big.from_u64(13) % big.from_u64(9)).int() == 4
|
||||||
assert (big.from_u64(7) % big.from_u64(5) ).int() == 2
|
assert (big.from_u64(7) % big.from_u64(5)).int() == 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_str() {
|
||||||
|
assert big.from_u64(255).str() == '255'
|
||||||
|
assert big.from_u64(127).str() == '127'
|
||||||
|
assert big.from_u64(1024).str() == '1024'
|
||||||
|
assert big.from_u64(4294967295).str() == '4294967295'
|
||||||
|
assert big.from_u64(4398046511104).str() == '4398046511104'
|
||||||
|
assert big.from_int(4294967295).str() == '18446744073709551615'
|
||||||
|
assert big.from_int(-1).str() == '18446744073709551615'
|
||||||
|
assert big.from_string('e'.repeat(80)).str() ==
|
||||||
|
'1993587900192849410235353592424915306962524220866209251950572167300738410728597846688097947807470'
|
||||||
|
}
|
||||||
|
|
||||||
fn test_factorial(){
|
fn test_factorial() {
|
||||||
f5 := big.factorial( big.from_u64(5) )
|
f5 := big.factorial(big.from_u64(5))
|
||||||
assert f5.hexstr() == '78'
|
assert f5.hexstr() == '78'
|
||||||
f100 := big.factorial( big.from_u64(100) )
|
f100 := big.factorial(big.from_u64(100))
|
||||||
assert f100.hexstr() == '1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000'
|
assert f100.hexstr() ==
|
||||||
|
'1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue