]> Cypherpunks repositories - gostls13.git/commitdiff
- better support for string conversions
authorRobert Griesemer <gri@golang.org>
Tue, 4 Nov 2008 19:37:19 +0000 (11:37 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 4 Nov 2008 19:37:19 +0000 (11:37 -0800)
- removed trailing tabs

R=r
OCL=18458
CL=18458

usr/gri/bignum/bignum.go
usr/gri/bignum/bignum_test.go

index 47232e67b9212e81964673ac7b6a993cdc1772e1..3670c37057d34059b5493289c8f9389106e05d06 100755 (executable)
@@ -180,7 +180,7 @@ func Mul11(x, y Digit) (Digit, Digit) {
        // z = z1*B + z0 = x*y
        z0 := (t1<<W2 + t0)&M;
        z1 := t2<<DW + (t1 + t0>>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)<<W2 + Digit(y2);
                for i := n-m; i >= 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;
 }
index eb7d3beeec5e0a308aa4e331304d54f59fe3a099..f277bb941f08f665de588d673ea0f10e32aac0b5 100644 (file)
@@ -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");
 }