diff --git a/usr/gri/bignum/bignum.go b/usr/gri/bignum/bignum.go index 47232e67b9..3670c37057 100755 --- a/usr/gri/bignum/bignum.go +++ b/usr/gri/bignum/bignum.go @@ -180,7 +180,7 @@ func Mul11(x, y Digit) (Digit, Digit) { // z = z1*B + z0 = x*y z0 := (t1<>W2)>>(W-W2); - + return z1, z0; } @@ -453,17 +453,17 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { assert(n+1 <= cap(x)); // space for one extra digit x = x[0 : n + 1]; assert(x[n] == 0); - + if m == 1 { // division by single digit // result is shifted left by 1 in place! x[0] = Div1(x[1 : n+1], x[0 : n], y[0]); - + } else if m > n { // y > x => quotient = 0, remainder = x // TODO in this case we shouldn't even unpack x and y m = n; - + } else { // general case assert(2 <= m && m <= n); @@ -478,12 +478,12 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { Mul1(y, y, Digit2(f)); } assert(B2/2 <= y[m-1] && y[m-1] < B2); // incorrect scaling - + y1, y2 := Digit(y[m-1]), Digit(y[m-2]); d2 := Digit(y1)<= 0; i-- { k := i+m; - + // compute trial digit (Knuth) var q Digit; { x0, x1, x2 := Digit(x[k]), Digit(x[k-1]), Digit(x[k-2]); @@ -496,14 +496,14 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { q-- } } - + // subtract y*q c := Digit(0); for j := 0; j < m; j++ { t := c + Digit(x[i+j]) - Digit(y[j])*q; c, x[i+j] = Digit(int64(t)>>W2), Digit2(t&M2); // requires arithmetic shift! } - + // correct if trial digit was too large if c + Digit(x[k]) != 0 { // add y @@ -516,10 +516,10 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { // correct trial digit q--; } - + x[k] = Digit2(q); } - + // undo normalization for remainder if f != 1 { c := Div1(x[0 : m], x[0 : m], Digit2(f)); @@ -553,9 +553,9 @@ func (x *Natural) Shl(s uint) *Natural { n := uint(len(x)); m := n + s/W; z := new(Natural, m+1); - + z[m] = Shl(z[m-n : m], x, s%W); - + return Normalize(z); } @@ -567,9 +567,9 @@ func (x *Natural) Shr(s uint) *Natural { m = 0; } z := new(Natural, m); - + Shr(z, x[n-m : n], s%W); - + return Normalize(z); } @@ -629,7 +629,7 @@ func (x *Natural) Cmp(y *Natural) int { i := n - 1; for i > 0 && x[i] == y[i] { i--; } - + d := 0; switch { case x[i] < y[i]: d = -1; @@ -679,7 +679,7 @@ func (x *Natural) String(base uint) string { if len(x) == 0 { return "0"; } - + // allocate buffer for conversion assert(2 <= base && base <= 16); n := (x.Log2() + 1) / Log2(Digit(base)) + 1; // +1: round up @@ -688,7 +688,7 @@ func (x *Natural) String(base uint) string { // don't destroy x t := new(Natural, len(x)); Or1(t, x, 0); // copy - + // convert i := n; for !t.IsZero() { @@ -730,7 +730,8 @@ func MulAdd1(x *Natural, d, c Digit) *Natural { // Determines base (octal, decimal, hexadecimal) if base == 0. -export func NatFromString(s string, base uint, slen *int) *Natural { +// Returns the number and base. +export func NatFromString(s string, base uint, slen *int) (*Natural, uint) { // determine base if necessary i, n := 0, len(s); if base == 0 { @@ -743,7 +744,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural { } } } - + // convert string assert(2 <= base && base <= 16); x := Nat(0); @@ -761,7 +762,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural { *slen = i; } - return x; + return x, base; } @@ -1104,7 +1105,8 @@ func (x *Integer) String(base uint) string { // Determines base (octal, decimal, hexadecimal) if base == 0. -export func IntFromString(s string, base uint, slen *int) *Integer { +// Returns the number and base. +export func IntFromString(s string, base uint, slen *int) (*Integer, uint) { // get sign, if any sign := false; if len(s) > 0 && (s[0] == '-' || s[0] == '+') { @@ -1112,14 +1114,15 @@ export func IntFromString(s string, base uint, slen *int) *Integer { s = s[1 : len(s)]; } - z := MakeInt(sign, NatFromString(s, base, slen)); + var mant *Natural; + mant, base = NatFromString(s, base, slen); // correct slen if necessary if slen != nil && sign { *slen++; } - return z; + return MakeInt(sign, mant), base; } @@ -1222,24 +1225,33 @@ func (x *Rational) String(base uint) string { // Determines base (octal, decimal, hexadecimal) if base == 0. -export func RatFromString(s string, base uint, slen *int) *Rational { +// Returns the number and base of the nominator. +export func RatFromString(s string, base uint, slen *int) (*Rational, uint) { // read nominator var alen, blen int; - a := IntFromString(s, base, &alen); + a, abase := IntFromString(s, base, &alen); b := Nat(1); - - // read denominator, if any - if alen < len(s) && s[alen] == '/' { - alen++; - if alen < len(s) { - b = NatFromString(s[alen : len(s)], base, &blen); + + // read denominator or fraction, if any + if alen < len(s) { + ch := s[alen]; + if ch == '/' { + alen++; + b, base = NatFromString(s[alen : len(s)], base, &blen); + } else if ch == '.' { + alen++; + b, base = NatFromString(s[alen : len(s)], abase, &blen); + assert(base == abase); + f := Nat(base).Pow(uint(blen)); + a = MakeInt(a.sign, a.mant.Mul(f).Add(b)); + b = f; } } - + // provide number of string bytes consumed if necessary if slen != nil { *slen = alen + blen; } - return MakeRat(a, b); + return MakeRat(a, b), abase; } diff --git a/usr/gri/bignum/bignum_test.go b/usr/gri/bignum/bignum_test.go index eb7d3beeec..f277bb941f 100644 --- a/usr/gri/bignum/bignum_test.go +++ b/usr/gri/bignum/bignum_test.go @@ -16,22 +16,40 @@ const ( ) +func NatFromString(s string, base uint, slen *int) *Big.Natural { + x, dummy := Big.NatFromString(s, base, slen); + return x; +} + + +func IntFromString(s string, base uint, slen *int) *Big.Integer { + x, dummy := Big.IntFromString(s, base, slen); + return x; +} + + +func RatFromString(s string, base uint, slen *int) *Big.Rational { + x, dummy := Big.RatFromString(s, base, slen); + return x; +} + + var ( nat_zero = Big.Nat(0); nat_one = Big.Nat(1); nat_two = Big.Nat(2); - - a = Big.NatFromString(sa, 10, nil); - b = Big.NatFromString(sb, 10, nil); - c = Big.NatFromString(sc, 10, nil); - p = Big.NatFromString(sp, 10, nil); + + a = NatFromString(sa, 10, nil); + b = NatFromString(sb, 10, nil); + c = NatFromString(sc, 10, nil); + p = NatFromString(sp, 10, nil); int_zero = Big.Int(0); int_one = Big.Int(1); int_two = Big.Int(2); - - ip = Big.IntFromString(sp, 10, nil); - + + ip = IntFromString(sp, 10, nil); + rat_zero = Big.Rat(0, 1); rat_half = Big.Rat(1, 2); rat_one = Big.Rat(1, 1); @@ -89,17 +107,17 @@ func NatConv() { test_msg = "NatConvB"; var slen int; - NAT_EQ(0, Big.NatFromString("0", 0, nil), nat_zero); - NAT_EQ(1, Big.NatFromString("123", 0, nil), Big.Nat(123)); - NAT_EQ(2, Big.NatFromString("077", 0, nil), Big.Nat(7*8 + 7)); - NAT_EQ(3, Big.NatFromString("0x1f", 0, nil), Big.Nat(1*16 + 15)); - NAT_EQ(4, Big.NatFromString("0x1fg", 0, &slen), Big.Nat(1*16 + 15)); + NAT_EQ(0, NatFromString("0", 0, nil), nat_zero); + NAT_EQ(1, NatFromString("123", 0, nil), Big.Nat(123)); + NAT_EQ(2, NatFromString("077", 0, nil), Big.Nat(7*8 + 7)); + NAT_EQ(3, NatFromString("0x1f", 0, nil), Big.Nat(1*16 + 15)); + NAT_EQ(4, NatFromString("0x1fg", 0, &slen), Big.Nat(1*16 + 15)); TEST(4, slen == 4); - + test_msg = "NatConvC"; t := c.Mul(c); for base := uint(2); base <= 16; base++ { - NAT_EQ(base, Big.NatFromString(t.String(base), base, nil), t); + NAT_EQ(base, NatFromString(t.String(base), base, nil), t); } } @@ -107,16 +125,16 @@ func NatConv() { func IntConv() { test_msg = "IntConv"; var slen int; - INT_EQ(0, Big.IntFromString("0", 0, nil), int_zero); - INT_EQ(1, Big.IntFromString("-0", 0, nil), int_zero); - INT_EQ(2, Big.IntFromString("123", 0, nil), Big.Int(123)); - INT_EQ(3, Big.IntFromString("-123", 0, nil), Big.Int(-123)); - INT_EQ(4, Big.IntFromString("077", 0, nil), Big.Int(7*8 + 7)); - INT_EQ(5, Big.IntFromString("-077", 0, nil), Big.Int(-(7*8 + 7))); - INT_EQ(6, Big.IntFromString("0x1f", 0, nil), Big.Int(1*16 + 15)); - INT_EQ(7, Big.IntFromString("-0x1f", 0, nil), Big.Int(-(1*16 + 15))); - INT_EQ(8, Big.IntFromString("0x1fg", 0, &slen), Big.Int(1*16 + 15)); - INT_EQ(9, Big.IntFromString("-0x1fg", 0, &slen), Big.Int(-(1*16 + 15))); + INT_EQ(0, IntFromString("0", 0, nil), int_zero); + INT_EQ(1, IntFromString("-0", 0, nil), int_zero); + INT_EQ(2, IntFromString("123", 0, nil), Big.Int(123)); + INT_EQ(3, IntFromString("-123", 0, nil), Big.Int(-123)); + INT_EQ(4, IntFromString("077", 0, nil), Big.Int(7*8 + 7)); + INT_EQ(5, IntFromString("-077", 0, nil), Big.Int(-(7*8 + 7))); + INT_EQ(6, IntFromString("0x1f", 0, nil), Big.Int(1*16 + 15)); + INT_EQ(7, IntFromString("-0x1f", 0, nil), Big.Int(-(1*16 + 15))); + INT_EQ(8, IntFromString("0x1fg", 0, &slen), Big.Int(1*16 + 15)); + INT_EQ(9, IntFromString("-0x1fg", 0, &slen), Big.Int(-(1*16 + 15))); TEST(10, slen == 5); } @@ -124,12 +142,16 @@ func IntConv() { func RatConv() { test_msg = "RatConv"; var slen int; - RAT_EQ(0, Big.RatFromString("0", 0, nil), rat_zero); - RAT_EQ(1, Big.RatFromString("0/", 0, nil), rat_zero); - RAT_EQ(2, Big.RatFromString("0/1", 0, nil), rat_zero); - RAT_EQ(3, Big.RatFromString("010/8", 0, nil), rat_one); - RAT_EQ(4, Big.RatFromString("20/0xa", 0, &slen), rat_two); - TEST(5, slen == 6); + RAT_EQ(0, RatFromString("0", 0, nil), rat_zero); + RAT_EQ(1, RatFromString("0/1", 0, nil), rat_zero); + RAT_EQ(2, RatFromString("0/01", 0, nil), rat_zero); + RAT_EQ(3, RatFromString("0x14/10", 0, &slen), rat_two); + TEST(4, slen == 7); + RAT_EQ(5, RatFromString("0.", 0, nil), rat_zero); + RAT_EQ(6, RatFromString("0.001f", 10, nil), Big.Rat(1, 1000)); + RAT_EQ(7, RatFromString("10101.0101", 2, nil), Big.Rat(0x155, 1<<4)); + RAT_EQ(8, RatFromString("-0003.145926", 10, &slen), Big.Rat(-3145926, 1000000)); + TEST(9, slen == 12); } @@ -213,11 +235,11 @@ func NatMul() { test_msg = "NatMulA"; NAT_EQ(0, Mul(c, nat_zero), nat_zero); NAT_EQ(1, Mul(c, nat_one), c); - + test_msg = "NatMulB"; NAT_EQ(0, b.Mul(Big.MulRange(0, 100)), nat_zero); NAT_EQ(1, b.Mul(Big.MulRange(21, 100)), c); - + test_msg = "NatMulC"; const n = 100; p := b.Mul(c).Shl(n); @@ -234,7 +256,7 @@ func NatDiv() { NAT_EQ(2, b.Div(c), nat_zero); NAT_EQ(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10)); NAT_EQ(5, c.Div(b), Big.MulRange(21, 100)); - + test_msg = "NatDivB"; const n = 100; p := Big.Fact(n); @@ -315,7 +337,7 @@ func NatShift() { test_msg = "NatShift1L"; TEST(0, b.Shl(0).Cmp(b) == 0); TEST(1, c.Shl(1).Cmp(c) > 0); - + test_msg = "NatShift1R"; TEST(0, b.Shr(0).Cmp(b) == 0); TEST(1, c.Shr(1).Cmp(c) < 0); @@ -349,7 +371,7 @@ func IntShift() { test_msg = "IntShift1L"; TEST(0, ip.Shl(0).Cmp(ip) == 0); TEST(1, ip.Shl(1).Cmp(ip) > 0); - + test_msg = "IntShift1R"; TEST(0, ip.Shr(0).Cmp(ip) == 0); TEST(1, ip.Shr(1).Cmp(ip) < 0); @@ -376,7 +398,7 @@ func IntShift() { p = p.Shr(1); } } - + test_msg = "IntShift4R"; //INT_EQ(0, Big.Int(-43).Shr(1), Big.Int(-43 >> 1)); //INT_EQ(1, ip.Neg().Shr(10), ip.Neg().Div(Big.Int(1).Shl(10))); @@ -456,17 +478,17 @@ func main() { NatGcd(); NatPow(); NatPop(); - + // Integers // TODO add more tests IntConv(); IntQuoRem(); IntDivMod(); IntShift(); - + // Rationals // TODO add more tests RatConv(); - + print("PASSED\n"); }