1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

bignum: move to math.big

This commit is contained in:
Alexander Medvednikov
2020-03-10 19:31:01 +01:00
parent f1274e34c2
commit 568d859fc0
3 changed files with 89 additions and 89 deletions

195
vlib/math/big/big.v Normal file
View File

@@ -0,0 +1,195 @@
module big
// Wrapper for https://github.com/kokke/tiny-bignum-c
#flag -I @VROOT/thirdparty/bignum
#flag @VROOT/thirdparty/bignum/bn.o
#include "bn.h"
const (
STRING_BUFFER_SIZE = 8192
)
pub struct Number {
array [32]u32
}
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_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_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_is_zero( a &Number) int
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
////////////////////////////////////////////////////////////
// conversion actions to/from big numbers:
pub fn new() Number {
return Number{}
}
pub fn from_int(i int) Number {
n := Number{}
C.bignum_from_int( &n, i)
return n
}
pub fn from_u64(u u64) Number {
n := Number{}
C.bignum_from_int( &n, u)
return n
}
pub fn from_string(s string) Number {
n := Number{}
C.bignum_from_string(&n, s.str, s.len)
return n
}
pub fn (n Number) int() int {
r := C.bignum_to_int(&n)
return r
}
pub fn (n Number) str() string {
// TODO: return a decimal representation of the bignumber n.
// A decimal representation will be easier to use in the repl
// but will be slower to calculate. Also, it is not implemented
// in the bn library.
return 'Number (in hex): ' + n.hexstr()
}
pub fn (n Number) hexstr() string {
mut buf := [STRING_BUFFER_SIZE]byte
C.bignum_to_string( &n, buf, STRING_BUFFER_SIZE)
// NB: bignum_to_string , returns the HEXADECIMAL representation of the bignum n
s := tos_clone( buf )
if s.len == 0 { return '0' }
return s
}
////////////////////////////////////////////////////////////
// overloaded ops for the numbers:
pub fn (a Number) + (b Number) Number {
c := Number{}
C.bignum_add(&a, &b, &c)
return c
}
pub fn (a Number) - (b Number) Number {
c := Number{}
C.bignum_sub(&a, &b, &c)
return c
}
pub fn (a Number) * (b Number) Number {
c := Number{}
C.bignum_mul(&a, &b, &c)
return c
}
pub fn (a Number) / (b Number) Number {
c := Number{}
C.bignum_div(&a, &b, &c)
return c
}
pub fn (a Number) % (b Number) Number {
c := Number{}
C.bignum_mod(&a, &b, &c)
return c
}
pub fn divmod( a &Number, b &Number, c &Number) Number {
d := Number{}
C.bignum_divmod( a, b, c, &d)
return d
}
////////////////////////////////////////////////////////////
pub fn cmp(a Number, b Number) int {
return C.bignum_cmp(&a,&b)
}
pub fn (a Number) is_zero() bool {
return C.bignum_is_zero(&a) != 0
}
pub fn (a mut Number) inc() {
C.bignum_inc(a)
}
pub fn (a mut Number) dec() {
C.bignum_dec(a)
}
pub fn pow(a Number, b Number) Number {
c := Number{}
C.bignum_pow(&a,&b,&c)
return c
}
pub fn (a Number) isqrt() Number {
b := Number{}
C.bignum_isqrt(&a,&b)
return b
}
////////////////////////////////////////////////////////////
pub fn b_and(a Number, b Number) Number {
c := Number{}
C.bignum_and(&a,&b,&c)
return c
}
pub fn b_or(a Number, b Number) Number {
c := Number{}
C.bignum_or(&a,&b,&c)
return c
}
pub fn b_xor(a Number, b Number) Number {
c := Number{}
C.bignum_xor(&a,&b,&c)
return c
}
pub fn (a Number) lshift(nbits int) Number {
b := Number{}
C.bignum_lshift(&a,&b,nbits)
return b
}
pub fn (a Number) rshift(nbits int) Number {
b := Number{}
C.bignum_rshift(&a,&b,nbits)
return b
}
pub fn (a Number) clone() Number {
b := Number{}
C.bignum_assign(&b,&a)
return b
}
////////////////////////////////////////////////////////////
pub fn factorial(nn Number) Number {
mut n := nn.clone()
mut a := nn.clone()
n.dec()
mut i:=1
for !n.is_zero() {
res := a * n
n.dec()
a = res
i++
}
return a
}
pub fn fact(n int) Number {
return factorial( from_int(n) )
}

86
vlib/math/big/big_test.v Normal file
View File

@@ -0,0 +1,86 @@
import big
fn test_new_big(){
n := big.new()
assert sizeof( big.Number ) == 128
assert n.hexstr() == '0'
}
fn test_from_int(){
assert big.from_int(255).hexstr() == 'ff'
assert big.from_int(127).hexstr() == '7f'
assert big.from_int(1024).hexstr() == '400'
assert big.from_int(2147483647).hexstr() == '7fffffff'
assert big.from_int(-1).hexstr() == 'ffffffffffffffff'
}
fn test_from_u64(){
assert big.from_u64(255).hexstr() == 'ff'
assert big.from_u64(127).hexstr() == '7f'
assert big.from_u64(1024).hexstr() == '400'
assert big.from_u64(4294967295).hexstr() == 'ffffffff'
assert big.from_u64(4398046511104).hexstr() == '40000000000'
assert big.from_u64(-1).hexstr() == 'ffffffffffffffff'
}
fn test_plus(){
a := big.from_u64(2)
b := big.from_u64(3)
c := a + b
assert c.hexstr() == '5'
assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800'
}
fn test_minus(){
a := big.from_u64(2)
b := big.from_u64(3)
c := b - a
assert c.hexstr() == '1'
e := big.from_u64(1024)
ee := e - e
assert ee.hexstr() == '0'
}
fn test_divide(){
a := big.from_u64(2)
b := big.from_u64(3)
c := b / a
assert c.hexstr() == '1'
assert (b % a ).hexstr() == '1'
e := big.from_u64(1024) // dec(1024) == hex(0x400)
ee := e / e
assert ee.hexstr() == '1'
assert (e / a).hexstr() == '200'
assert (e / (a*a)).hexstr() == '100'
}
fn test_multiply(){
a := big.from_u64(2)
b := big.from_u64(3)
c := b * a
assert c.hexstr() == '6'
e := big.from_u64(1024)
e2 := e * e
e4 := e2 * e2
e8 := e2 * e2 * e2 * e2
e9 := e8 + big.from_u64(1)
d := ((e9 * e9) + b) * c
assert e4.hexstr() == '10000000000'
assert e8.hexstr() == '100000000000000000000'
assert e9.hexstr() == '100000000000000000001'
assert d.hexstr() == '60000000000000000000c00000000000000000018'
}
fn test_mod(){
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(7) % big.from_u64(5) ).int() == 2
}
fn test_factorial(){
f5 := big.factorial( big.from_u64(5) )
assert f5.hexstr() == '78'
f100 := big.factorial( big.from_u64(100) )
assert f100.hexstr() == '1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000'
}