]> Cypherpunks repositories - gostls13.git/commitdiff
- split bignum package into 3 files
authorRobert Griesemer <gri@golang.org>
Tue, 21 Jul 2009 21:28:59 +0000 (14:28 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 21 Jul 2009 21:28:59 +0000 (14:28 -0700)
- use array for common small values
- integer.go, rational.go don't contain changes besides the added file header

R=rsc
DELTA=1475  (748 added, 713 deleted, 14 changed)
OCL=31939
CL=31942

src/pkg/bignum/Makefile
src/pkg/bignum/bignum.go
src/pkg/bignum/bignum_test.go
src/pkg/bignum/integer.go [new file with mode: 0644]
src/pkg/bignum/rational.go [new file with mode: 0644]

index 098b9097536b8410bd1979aa0d06eaa074dd27b4..12d1f3193d52a4bc1f92d8709b337bd14c9233c8 100644 (file)
@@ -2,8 +2,9 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
+
 # DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
+# gobuild -m bignum.go integer.go rational.go >Makefile
 
 D=
 
@@ -20,7 +21,7 @@ test: packages
 
 coverage: packages
        gotest
-       6cov -g `pwd` | grep -v '_test\.go:'
+       6cov -g $$(pwd) | grep -v '_test\.go:'
 
 %.$O: %.go
        $(GC) -I_obj $*.go
@@ -34,14 +35,28 @@ coverage: packages
 O1=\
        bignum.$O\
 
+O2=\
+       integer.$O\
+
+O3=\
+       rational.$O\
+
 
-phases: a1
+phases: a1 a2 a3
 _obj$D/bignum.a: phases
 
 a1: $(O1)
        $(AR) grc _obj$D/bignum.a bignum.$O
        rm -f $(O1)
 
+a2: $(O2)
+       $(AR) grc _obj$D/bignum.a integer.$O
+       rm -f $(O2)
+
+a3: $(O3)
+       $(AR) grc _obj$D/bignum.a rational.$O
+       rm -f $(O3)
+
 
 newpkg: clean
        mkdir -p _obj$D
@@ -49,6 +64,8 @@ newpkg: clean
 
 $(O1): newpkg
 $(O2): a1
+$(O3): a2
+$(O4): a3
 
 nuke: clean
        rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bignum.a
index 91a207dd410a297206c186dd256c2152982b1db1..71bf66d76110be2292e6a05868b96d9ead718ae5 100755 (executable)
@@ -109,23 +109,24 @@ func dump(x []digit) {
 //
 type Natural []digit;
 
-var (
-       natZero = Natural{};
-       natOne = Natural{1};
-       natTwo = Natural{2};
-       natTen = Natural{10};
-)
+
+// Common small values - allocate once.
+var nat [16]Natural;
+
+func init() {
+       nat[0] = Natural{};  // zero has no digits
+       for i := 1; i < len(nat); i++ {
+               nat[i] = Natural{digit(i)};
+       }
+}
 
 
 // Nat creates a small natural number with value x.
 //
 func Nat(x uint64) Natural {
        // avoid allocation for common small values
-       switch x {
-       case 0: return natZero;
-       case 1: return natOne;
-       case 2: return natTwo;
-       case 10: return natTen;
+       if x < uint64(len(nat)) {
+               return nat[x];
        }
 
        // single-digit values
@@ -851,7 +852,7 @@ func NatFromString(s string, base uint) (Natural, uint, int) {
 
        // convert string
        assert(2 <= base && base <= 16);
-       x := Nat(0);
+       x := nat[0];
        for ; i < n; i++ {
                d := hexvalue(s[i]);
                if d < base {
@@ -891,7 +892,7 @@ func (x Natural) Pop() uint {
 // Pow computes x to the power of n.
 //
 func (xp Natural) Pow(n uint) Natural {
-       z := Nat(1);
+       z := nat[1];
        x := xp;
        for n > 0 {
                // z * x^n == x^n0
@@ -909,7 +910,7 @@ func (xp Natural) Pow(n uint) Natural {
 //
 func MulRange(a, b uint) Natural {
        switch {
-       case a > b: return Nat(1);
+       case a > b: return nat[1];
        case a == b: return Nat(uint64(a));
        case a + 1 == b: return Nat(uint64(a)).Mul(Nat(uint64(b)));
        }
@@ -945,713 +946,3 @@ func (x Natural) Gcd(y Natural) Natural {
        }
        return a;
 }
-
-
-// ----------------------------------------------------------------------------
-// Integer numbers
-//
-// Integers are normalized if the mantissa is normalized and the sign is
-// false for mant == 0. Use MakeInt to create normalized Integers.
-
-// Integer represents a signed integer value of arbitrary precision.
-//
-type Integer struct {
-       sign bool;
-       mant Natural;
-}
-
-
-// MakeInt makes an integer given a sign and a mantissa.
-// The number is positive (>= 0) if sign is false or the
-// mantissa is zero; it is negative otherwise.
-//
-func MakeInt(sign bool, mant Natural) *Integer {
-       if mant.IsZero() {
-               sign = false;  // normalize
-       }
-       return &Integer{sign, mant};
-}
-
-
-// Int creates a small integer with value x.
-//
-func Int(x int64) *Integer {
-       var ux uint64;
-       if x < 0 {
-               // For the most negative x, -x == x, and
-               // the bit pattern has the correct value.
-               ux = uint64(-x);
-       } else {
-               ux = uint64(x);
-       }
-       return MakeInt(x < 0, Nat(ux));
-}
-
-
-// Value returns the value of x, if x fits into an int64;
-// otherwise the result is undefined.
-//
-func (x *Integer) Value() int64 {
-       z := int64(x.mant.Value());
-       if x.sign {
-               z = -z;
-       }
-       return z;
-}
-
-
-// Abs returns the absolute value of x.
-//
-func (x *Integer) Abs() Natural {
-       return x.mant;
-}
-
-
-// Predicates
-
-// IsEven returns true iff x is divisible by 2.
-//
-func (x *Integer) IsEven() bool {
-       return x.mant.IsEven();
-}
-
-
-// IsOdd returns true iff x is not divisible by 2.
-//
-func (x *Integer) IsOdd() bool {
-       return x.mant.IsOdd();
-}
-
-
-// IsZero returns true iff x == 0.
-//
-func (x *Integer) IsZero() bool {
-       return x.mant.IsZero();
-}
-
-
-// IsNeg returns true iff x < 0.
-//
-func (x *Integer) IsNeg() bool {
-       return x.sign && !x.mant.IsZero()
-}
-
-
-// IsPos returns true iff x >= 0.
-//
-func (x *Integer) IsPos() bool {
-       return !x.sign && !x.mant.IsZero()
-}
-
-
-// Operations
-
-// Neg returns the negated value of x.
-//
-func (x *Integer) Neg() *Integer {
-       return MakeInt(!x.sign, x.mant);
-}
-
-
-// Add returns the sum x + y.
-//
-func (x *Integer) Add(y *Integer) *Integer {
-       var z *Integer;
-       if x.sign == y.sign {
-               // x + y == x + y
-               // (-x) + (-y) == -(x + y)
-               z = MakeInt(x.sign, x.mant.Add(y.mant));
-       } else {
-               // x + (-y) == x - y == -(y - x)
-               // (-x) + y == y - x == -(x - y)
-               if x.mant.Cmp(y.mant) >= 0 {
-                       z = MakeInt(false, x.mant.Sub(y.mant));
-               } else {
-                       z = MakeInt(true, y.mant.Sub(x.mant));
-               }
-       }
-       if x.sign {
-               z.sign = !z.sign;
-       }
-       return z;
-}
-
-
-// Sub returns the difference x - y.
-//
-func (x *Integer) Sub(y *Integer) *Integer {
-       var z *Integer;
-       if x.sign != y.sign {
-               // x - (-y) == x + y
-               // (-x) - y == -(x + y)
-               z = MakeInt(false, x.mant.Add(y.mant));
-       } else {
-               // x - y == x - y == -(y - x)
-               // (-x) - (-y) == y - x == -(x - y)
-               if x.mant.Cmp(y.mant) >= 0 {
-                       z = MakeInt(false, x.mant.Sub(y.mant));
-               } else {
-                       z = MakeInt(true, y.mant.Sub(x.mant));
-               }
-       }
-       if x.sign {
-               z.sign = !z.sign;
-       }
-       return z;
-}
-
-
-// Mul returns the product x * y.
-//
-func (x *Integer) Mul(y *Integer) *Integer {
-       // x * y == x * y
-       // x * (-y) == -(x * y)
-       // (-x) * y == -(x * y)
-       // (-x) * (-y) == x * y
-       return MakeInt(x.sign != y.sign, x.mant.Mul(y.mant));
-}
-
-
-// MulNat returns the product x * y, where y is a (unsigned) natural number.
-//
-func (x *Integer) MulNat(y Natural) *Integer {
-       // x * y == x * y
-       // (-x) * y == -(x * y)
-       return MakeInt(x.sign, x.mant.Mul(y));
-}
-
-
-// Quo returns the quotient q = x / y for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-// Quo and Rem implement T-division and modulus (like C99):
-//
-//   q = x.Quo(y) = trunc(x/y)  (truncation towards zero)
-//   r = x.Rem(y) = x - y*q
-//
-// (Daan Leijen, ``Division and Modulus for Computer Scientists''.)
-//
-func (x *Integer) Quo(y *Integer) *Integer {
-       // x / y == x / y
-       // x / (-y) == -(x / y)
-       // (-x) / y == -(x / y)
-       // (-x) / (-y) == x / y
-       return MakeInt(x.sign != y.sign, x.mant.Div(y.mant));
-}
-
-
-// Rem returns the remainder r of the division x / y for y != 0,
-// with r = x - y*x.Quo(y). Unless r is zero, its sign corresponds
-// to the sign of x.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Integer) Rem(y *Integer) *Integer {
-       // x % y == x % y
-       // x % (-y) == x % y
-       // (-x) % y == -(x % y)
-       // (-x) % (-y) == -(x % y)
-       return MakeInt(x.sign, x.mant.Mod(y.mant));
-}
-
-
-// QuoRem returns the pair (x.Quo(y), x.Rem(y)) for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) {
-       q, r := x.mant.DivMod(y.mant);
-       return MakeInt(x.sign != y.sign, q), MakeInt(x.sign, r);
-}
-
-
-// Div returns the quotient q = x / y for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-// Div and Mod implement Euclidian division and modulus:
-//
-//   q = x.Div(y)
-//   r = x.Mod(y) with: 0 <= r < |q| and: y = x*q + r
-//
-// (Raymond T. Boute, ``The Euclidian definition of the functions
-// div and mod''. ACM Transactions on Programming Languages and
-// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
-// ACM press.)
-//
-func (x *Integer) Div(y *Integer) *Integer {
-       q, r := x.QuoRem(y);
-       if r.IsNeg() {
-               if y.IsPos() {
-                       q = q.Sub(Int(1));
-               } else {
-                       q = q.Add(Int(1));
-               }
-       }
-       return q;
-}
-
-
-// Mod returns the modulus r of the division x / y for y != 0,
-// with r = x - y*x.Div(y). r is always positive.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Integer) Mod(y *Integer) *Integer {
-       r := x.Rem(y);
-       if r.IsNeg() {
-               if y.IsPos() {
-                       r = r.Add(y);
-               } else {
-                       r = r.Sub(y);
-               }
-       }
-       return r;
-}
-
-
-// DivMod returns the pair (x.Div(y), x.Mod(y)).
-//
-func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) {
-       q, r := x.QuoRem(y);
-       if r.IsNeg() {
-               if y.IsPos() {
-                       q = q.Sub(Int(1));
-                       r = r.Add(y);
-               } else {
-                       q = q.Add(Int(1));
-                       r = r.Sub(y);
-               }
-       }
-       return q, r;
-}
-
-
-// Shl implements ``shift left'' x << s. It returns x * 2^s.
-//
-func (x *Integer) Shl(s uint) *Integer {
-       return MakeInt(x.sign, x.mant.Shl(s));
-}
-
-
-// The bitwise operations on integers are defined on the 2's-complement
-// representation of integers. From
-//
-//   -x == ^x + 1  (1)  2's complement representation
-//
-// follows:
-//
-//   -(x) == ^(x) + 1
-//   -(-x) == ^(-x) + 1
-//   x-1 == ^(-x)
-//   ^(x-1) == -x  (2)
-//
-// Using (1) and (2), operations on negative integers of the form -x are
-// converted to operations on negated positive integers of the form ~(x-1).
-
-
-// Shr implements ``shift right'' x >> s. It returns x / 2^s.
-//
-func (x *Integer) Shr(s uint) *Integer {
-       if x.sign {
-               // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
-               return MakeInt(true, x.mant.Sub(natOne).Shr(s).Add(natOne));
-       }
-       
-       return MakeInt(false, x.mant.Shr(s));
-}
-
-
-// Not returns the ``bitwise not'' ^x for the 2's-complement representation of x.
-func (x *Integer) Not() *Integer {
-       if x.sign {
-               // ^(-x) == ^(^(x-1)) == x-1
-               return MakeInt(false, x.mant.Sub(natOne));
-       }
-
-       // ^x == -x-1 == -(x+1)
-       return MakeInt(true, x.mant.Add(natOne));
-}
-
-
-// And returns the ``bitwise and'' x & y for the 2's-complement representation of x and y.
-//
-func (x *Integer) And(y *Integer) *Integer {
-       if x.sign == y.sign {
-               if x.sign {
-                       // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
-                       return MakeInt(true, x.mant.Sub(natOne).Or(y.mant.Sub(natOne)).Add(natOne));
-               }
-
-               // x & y == x & y
-               return MakeInt(false, x.mant.And(y.mant));
-       }
-
-       // x.sign != y.sign
-       if x.sign {
-               x, y = y, x;  // & is symmetric
-       }
-
-       // x & (-y) == x & ^(y-1) == x &^ (y-1)
-       return MakeInt(false, x.mant.AndNot(y.mant.Sub(natOne)));
-}
-
-
-// AndNot returns the ``bitwise clear'' x &^ y for the 2's-complement representation of x and y.
-//
-func (x *Integer) AndNot(y *Integer) *Integer {
-       if x.sign == y.sign {
-               if x.sign {
-                       // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
-                       return MakeInt(false, y.mant.Sub(natOne).AndNot(x.mant.Sub(natOne)));
-               }
-
-               // x &^ y == x &^ y
-               return MakeInt(false, x.mant.AndNot(y.mant));
-       }
-
-       if x.sign {
-               // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
-               return MakeInt(true, x.mant.Sub(natOne).Or(y.mant).Add(natOne));
-       }
-
-       // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
-       return MakeInt(false, x.mant.And(y.mant.Sub(natOne)));
-}
-
-
-// Or returns the ``bitwise or'' x | y for the 2's-complement representation of x and y.
-//
-func (x *Integer) Or(y *Integer) *Integer {
-       if x.sign == y.sign {
-               if x.sign {
-                       // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
-                       return MakeInt(true, x.mant.Sub(natOne).And(y.mant.Sub(natOne)).Add(natOne));
-               }
-
-               // x | y == x | y
-               return MakeInt(false, x.mant.Or(y.mant));
-       }
-
-       // x.sign != y.sign
-       if x.sign {
-               x, y = y, x;  // | or symmetric
-       }
-
-       // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
-       return MakeInt(true, y.mant.Sub(natOne).AndNot(x.mant).Add(natOne));
-}
-
-
-// Xor returns the ``bitwise xor'' x | y for the 2's-complement representation of x and y.
-//
-func (x *Integer) Xor(y *Integer) *Integer {
-       if x.sign == y.sign {
-               if x.sign {
-                       // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
-                       return MakeInt(false, x.mant.Sub(natOne).Xor(y.mant.Sub(natOne)));
-               }
-
-               // x ^ y == x ^ y
-               return MakeInt(false, x.mant.Xor(y.mant));
-       }
-
-       // x.sign != y.sign
-       if x.sign {
-               x, y = y, x;  // ^ is symmetric
-       }
-
-       // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
-       return MakeInt(true, x.mant.Xor(y.mant.Sub(natOne)).Add(natOne));
-}
-
-
-// Cmp compares x and y. The result is an int value
-//
-//   <  0 if x <  y
-//   == 0 if x == y
-//   >  0 if x >  y
-//
-func (x *Integer) Cmp(y *Integer) int {
-       // x cmp y == x cmp y
-       // x cmp (-y) == x
-       // (-x) cmp y == y
-       // (-x) cmp (-y) == -(x cmp y)
-       var r int;
-       switch {
-       case x.sign == y.sign:
-               r = x.mant.Cmp(y.mant);
-               if x.sign {
-                       r = -r;
-               }
-       case x.sign: r = -1;
-       case y.sign: r = 1;
-       }
-       return r;
-}
-
-
-// ToString converts x to a string for a given base, with 2 <= base <= 16.
-//
-func (x *Integer) ToString(base uint) string {
-       if x.mant.IsZero() {
-               return "0";
-       }
-       var s string;
-       if x.sign {
-               s = "-";
-       }
-       return s + x.mant.ToString(base);
-}
-
-
-// String converts x to its decimal string representation.
-// x.String() is the same as x.ToString(10).
-//
-func (x *Integer) String() string {
-       return x.ToString(10);
-}
-
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
-//
-func (x *Integer) Format(h fmt.State, c int) {
-       fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
-}
-
-
-// IntFromString returns the integer corresponding to the
-// longest possible prefix of s representing an integer in a
-// given conversion base, the actual conversion base used, and
-// the prefix length. The syntax of integers follows the syntax
-// of signed integer literals in Go.
-//
-// If the base argument is 0, the string prefix determines the actual
-// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
-// ``0'' prefix selects base 8. Otherwise the selected base is 10.
-//
-func IntFromString(s string, base uint) (*Integer, uint, int) {
-       // skip sign, if any
-       i0 := 0;
-       if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
-               i0 = 1;
-       }
-
-       mant, base, slen := NatFromString(s[i0 : len(s)], base);
-
-       return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen;
-}
-
-
-// ----------------------------------------------------------------------------
-// Rational numbers
-
-// Rational represents a quotient a/b of arbitrary precision.
-//
-type Rational struct {
-       a *Integer;  // numerator
-       b Natural;  // denominator
-}
-
-
-// MakeRat makes a rational number given a numerator a and a denominator b.
-//
-func MakeRat(a *Integer, b Natural) *Rational {
-       f := a.mant.Gcd(b);  // f > 0
-       if f.Cmp(Nat(1)) != 0 {
-               a = MakeInt(a.sign, a.mant.Div(f));
-               b = b.Div(f);
-       }
-       return &Rational{a, b};
-}
-
-
-// Rat creates a small rational number with value a0/b0.
-//
-func Rat(a0 int64, b0 int64) *Rational {
-       a, b := Int(a0), Int(b0);
-       if b.sign {
-               a = a.Neg();
-       }
-       return MakeRat(a, b.mant);
-}
-
-
-// Value returns the numerator and denominator of x.
-//
-func (x *Rational) Value() (numerator *Integer, denominator Natural) {
-       return x.a, x.b;
-}
-
-
-// Predicates
-
-// IsZero returns true iff x == 0.
-//
-func (x *Rational) IsZero() bool {
-       return x.a.IsZero();
-}
-
-
-// IsNeg returns true iff x < 0.
-//
-func (x *Rational) IsNeg() bool {
-       return x.a.IsNeg();
-}
-
-
-// IsPos returns true iff x > 0.
-//
-func (x *Rational) IsPos() bool {
-       return x.a.IsPos();
-}
-
-
-// IsInt returns true iff x can be written with a denominator 1
-// in the form x == x'/1; i.e., if x is an integer value.
-//
-func (x *Rational) IsInt() bool {
-       return x.b.Cmp(Nat(1)) == 0;
-}
-
-
-// Operations
-
-// Neg returns the negated value of x.
-//
-func (x *Rational) Neg() *Rational {
-       return MakeRat(x.a.Neg(), x.b);
-}
-
-
-// Add returns the sum x + y.
-//
-func (x *Rational) Add(y *Rational) *Rational {
-       return MakeRat((x.a.MulNat(y.b)).Add(y.a.MulNat(x.b)), x.b.Mul(y.b));
-}
-
-
-// Sub returns the difference x - y.
-//
-func (x *Rational) Sub(y *Rational) *Rational {
-       return MakeRat((x.a.MulNat(y.b)).Sub(y.a.MulNat(x.b)), x.b.Mul(y.b));
-}
-
-
-// Mul returns the product x * y.
-//
-func (x *Rational) Mul(y *Rational) *Rational {
-       return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b));
-}
-
-
-// Quo returns the quotient x / y for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Rational) Quo(y *Rational) *Rational {
-       a := x.a.MulNat(y.b);
-       b := y.a.MulNat(x.b);
-       if b.IsNeg() {
-               a = a.Neg();
-       }
-       return MakeRat(a, b.mant);
-}
-
-
-// Cmp compares x and y. The result is an int value
-//
-//   <  0 if x <  y
-//   == 0 if x == y
-//   >  0 if x >  y
-//
-func (x *Rational) Cmp(y *Rational) int {
-       return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b));
-}
-
-
-// ToString converts x to a string for a given base, with 2 <= base <= 16.
-// The string representation is of the form "n" if x is an integer; otherwise
-// it is of form "n/d".
-//
-func (x *Rational) ToString(base uint) string {
-       s := x.a.ToString(base);
-       if !x.IsInt() {
-               s += "/" + x.b.ToString(base);
-       }
-       return s;
-}
-
-
-// String converts x to its decimal string representation.
-// x.String() is the same as x.ToString(10).
-//
-func (x *Rational) String() string {
-       return x.ToString(10);
-}
-
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
-//
-func (x *Rational) Format(h fmt.State, c int) {
-       fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
-}
-
-
-// RatFromString returns the rational number corresponding to the
-// longest possible prefix of s representing a rational number in a
-// given conversion base, the actual conversion base used, and the
-// prefix length. The syntax of a rational number is:
-//
-//     rational = mantissa [exponent] .
-//     mantissa = integer ('/' natural | '.' natural) .
-//     exponent = ('e'|'E') integer .
-//
-// If the base argument is 0, the string prefix determines the actual
-// conversion base for the mantissa. A prefix of ``0x'' or ``0X'' selects
-// base 16; the ``0'' prefix selects base 8. Otherwise the selected base is 10.
-// If the mantissa is represented via a division, both the numerator and
-// denominator may have different base prefixes; in that case the base of
-// of the numerator is returned. If the mantissa contains a decimal point,
-// the base for the fractional part is the same as for the part before the
-// decimal point and the fractional part does not accept a base prefix.
-// The base for the exponent is always 10. 
-//
-func RatFromString(s string, base uint) (*Rational, uint, int) {
-       // read numerator
-       a, abase, alen := IntFromString(s, base);
-       b := Nat(1);
-
-       // read denominator or fraction, if any
-       var blen int;
-       if alen < len(s) {
-               ch := s[alen];
-               if ch == '/' {
-                       alen++;
-                       b, base, blen = NatFromString(s[alen : len(s)], base);
-               } else if ch == '.' {
-                       alen++;
-                       b, base, blen = NatFromString(s[alen : len(s)], abase);
-                       assert(base == abase);
-                       f := Nat(uint64(base)).Pow(uint(blen));
-                       a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
-                       b = f;
-               }
-       }
-
-       // read exponent, if any
-       rlen := alen + blen;
-       if rlen < len(s) {
-               ch := s[rlen];
-               if ch == 'e' || ch == 'E' {
-                       rlen++;
-                       e, _, elen := IntFromString(s[rlen : len(s)], 10);
-                       rlen += elen;
-                       m := Nat(10).Pow(uint(e.mant.Value()));
-                       if e.sign {
-                               b = b.Mul(m);
-                       } else {
-                               a = a.MulNat(m);
-                       }
-               }
-       }
-
-       return MakeRat(a, b), base, rlen;
-}
index d07446bb4698d5c16fcfed1ce52f46f2d7ccae08..d691da2327f1ada0f22c7c977dbd28f106e8170a 100644 (file)
@@ -116,6 +116,11 @@ func TestNatConv(t *testing.T) {
                test(200 + uint(i), natFromString(e.s, 0, nil).Value() == e.x);
        }
 
+       test_msg = "NatConvB";
+       for i := uint(0); i < 100; i++ {
+               test(i, Nat(uint64(i)).String() == fmt.Sprintf("%d", i));
+       }
+
        test_msg = "NatConvC";
        z := uint64(7);
        for i := uint(0); i <= 64; i++ {
diff --git a/src/pkg/bignum/integer.go b/src/pkg/bignum/integer.go
new file mode 100644 (file)
index 0000000..f3c111d
--- /dev/null
@@ -0,0 +1,500 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Integer numbers
+//
+// Integers are normalized if the mantissa is normalized and the sign is
+// false for mant == 0. Use MakeInt to create normalized Integers.
+
+package bignum
+
+import "bignum"
+import "fmt"
+
+
+// Integer represents a signed integer value of arbitrary precision.
+//
+type Integer struct {
+       sign bool;
+       mant Natural;
+}
+
+
+// MakeInt makes an integer given a sign and a mantissa.
+// The number is positive (>= 0) if sign is false or the
+// mantissa is zero; it is negative otherwise.
+//
+func MakeInt(sign bool, mant Natural) *Integer {
+       if mant.IsZero() {
+               sign = false;  // normalize
+       }
+       return &Integer{sign, mant};
+}
+
+
+// Int creates a small integer with value x.
+//
+func Int(x int64) *Integer {
+       var ux uint64;
+       if x < 0 {
+               // For the most negative x, -x == x, and
+               // the bit pattern has the correct value.
+               ux = uint64(-x);
+       } else {
+               ux = uint64(x);
+       }
+       return MakeInt(x < 0, Nat(ux));
+}
+
+
+// Value returns the value of x, if x fits into an int64;
+// otherwise the result is undefined.
+//
+func (x *Integer) Value() int64 {
+       z := int64(x.mant.Value());
+       if x.sign {
+               z = -z;
+       }
+       return z;
+}
+
+
+// Abs returns the absolute value of x.
+//
+func (x *Integer) Abs() Natural {
+       return x.mant;
+}
+
+
+// Predicates
+
+// IsEven returns true iff x is divisible by 2.
+//
+func (x *Integer) IsEven() bool {
+       return x.mant.IsEven();
+}
+
+
+// IsOdd returns true iff x is not divisible by 2.
+//
+func (x *Integer) IsOdd() bool {
+       return x.mant.IsOdd();
+}
+
+
+// IsZero returns true iff x == 0.
+//
+func (x *Integer) IsZero() bool {
+       return x.mant.IsZero();
+}
+
+
+// IsNeg returns true iff x < 0.
+//
+func (x *Integer) IsNeg() bool {
+       return x.sign && !x.mant.IsZero()
+}
+
+
+// IsPos returns true iff x >= 0.
+//
+func (x *Integer) IsPos() bool {
+       return !x.sign && !x.mant.IsZero()
+}
+
+
+// Operations
+
+// Neg returns the negated value of x.
+//
+func (x *Integer) Neg() *Integer {
+       return MakeInt(!x.sign, x.mant);
+}
+
+
+// Add returns the sum x + y.
+//
+func (x *Integer) Add(y *Integer) *Integer {
+       var z *Integer;
+       if x.sign == y.sign {
+               // x + y == x + y
+               // (-x) + (-y) == -(x + y)
+               z = MakeInt(x.sign, x.mant.Add(y.mant));
+       } else {
+               // x + (-y) == x - y == -(y - x)
+               // (-x) + y == y - x == -(x - y)
+               if x.mant.Cmp(y.mant) >= 0 {
+                       z = MakeInt(false, x.mant.Sub(y.mant));
+               } else {
+                       z = MakeInt(true, y.mant.Sub(x.mant));
+               }
+       }
+       if x.sign {
+               z.sign = !z.sign;
+       }
+       return z;
+}
+
+
+// Sub returns the difference x - y.
+//
+func (x *Integer) Sub(y *Integer) *Integer {
+       var z *Integer;
+       if x.sign != y.sign {
+               // x - (-y) == x + y
+               // (-x) - y == -(x + y)
+               z = MakeInt(false, x.mant.Add(y.mant));
+       } else {
+               // x - y == x - y == -(y - x)
+               // (-x) - (-y) == y - x == -(x - y)
+               if x.mant.Cmp(y.mant) >= 0 {
+                       z = MakeInt(false, x.mant.Sub(y.mant));
+               } else {
+                       z = MakeInt(true, y.mant.Sub(x.mant));
+               }
+       }
+       if x.sign {
+               z.sign = !z.sign;
+       }
+       return z;
+}
+
+
+// Mul returns the product x * y.
+//
+func (x *Integer) Mul(y *Integer) *Integer {
+       // x * y == x * y
+       // x * (-y) == -(x * y)
+       // (-x) * y == -(x * y)
+       // (-x) * (-y) == x * y
+       return MakeInt(x.sign != y.sign, x.mant.Mul(y.mant));
+}
+
+
+// MulNat returns the product x * y, where y is a (unsigned) natural number.
+//
+func (x *Integer) MulNat(y Natural) *Integer {
+       // x * y == x * y
+       // (-x) * y == -(x * y)
+       return MakeInt(x.sign, x.mant.Mul(y));
+}
+
+
+// Quo returns the quotient q = x / y for y != 0.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+// Quo and Rem implement T-division and modulus (like C99):
+//
+//   q = x.Quo(y) = trunc(x/y)  (truncation towards zero)
+//   r = x.Rem(y) = x - y*q
+//
+// (Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+//
+func (x *Integer) Quo(y *Integer) *Integer {
+       // x / y == x / y
+       // x / (-y) == -(x / y)
+       // (-x) / y == -(x / y)
+       // (-x) / (-y) == x / y
+       return MakeInt(x.sign != y.sign, x.mant.Div(y.mant));
+}
+
+
+// Rem returns the remainder r of the division x / y for y != 0,
+// with r = x - y*x.Quo(y). Unless r is zero, its sign corresponds
+// to the sign of x.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+func (x *Integer) Rem(y *Integer) *Integer {
+       // x % y == x % y
+       // x % (-y) == x % y
+       // (-x) % y == -(x % y)
+       // (-x) % (-y) == -(x % y)
+       return MakeInt(x.sign, x.mant.Mod(y.mant));
+}
+
+
+// QuoRem returns the pair (x.Quo(y), x.Rem(y)) for y != 0.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) {
+       q, r := x.mant.DivMod(y.mant);
+       return MakeInt(x.sign != y.sign, q), MakeInt(x.sign, r);
+}
+
+
+// Div returns the quotient q = x / y for y != 0.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+// Div and Mod implement Euclidian division and modulus:
+//
+//   q = x.Div(y)
+//   r = x.Mod(y) with: 0 <= r < |q| and: y = x*q + r
+//
+// (Raymond T. Boute, ``The Euclidian definition of the functions
+// div and mod''. ACM Transactions on Programming Languages and
+// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
+// ACM press.)
+//
+func (x *Integer) Div(y *Integer) *Integer {
+       q, r := x.QuoRem(y);
+       if r.IsNeg() {
+               if y.IsPos() {
+                       q = q.Sub(Int(1));
+               } else {
+                       q = q.Add(Int(1));
+               }
+       }
+       return q;
+}
+
+
+// Mod returns the modulus r of the division x / y for y != 0,
+// with r = x - y*x.Div(y). r is always positive.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+func (x *Integer) Mod(y *Integer) *Integer {
+       r := x.Rem(y);
+       if r.IsNeg() {
+               if y.IsPos() {
+                       r = r.Add(y);
+               } else {
+                       r = r.Sub(y);
+               }
+       }
+       return r;
+}
+
+
+// DivMod returns the pair (x.Div(y), x.Mod(y)).
+//
+func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) {
+       q, r := x.QuoRem(y);
+       if r.IsNeg() {
+               if y.IsPos() {
+                       q = q.Sub(Int(1));
+                       r = r.Add(y);
+               } else {
+                       q = q.Add(Int(1));
+                       r = r.Sub(y);
+               }
+       }
+       return q, r;
+}
+
+
+// Shl implements ``shift left'' x << s. It returns x * 2^s.
+//
+func (x *Integer) Shl(s uint) *Integer {
+       return MakeInt(x.sign, x.mant.Shl(s));
+}
+
+
+// The bitwise operations on integers are defined on the 2's-complement
+// representation of integers. From
+//
+//   -x == ^x + 1  (1)  2's complement representation
+//
+// follows:
+//
+//   -(x) == ^(x) + 1
+//   -(-x) == ^(-x) + 1
+//   x-1 == ^(-x)
+//   ^(x-1) == -x  (2)
+//
+// Using (1) and (2), operations on negative integers of the form -x are
+// converted to operations on negated positive integers of the form ~(x-1).
+
+
+// Shr implements ``shift right'' x >> s. It returns x / 2^s.
+//
+func (x *Integer) Shr(s uint) *Integer {
+       if x.sign {
+               // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+               return MakeInt(true, x.mant.Sub(nat[1]).Shr(s).Add(nat[1]));
+       }
+       
+       return MakeInt(false, x.mant.Shr(s));
+}
+
+
+// Not returns the ``bitwise not'' ^x for the 2's-complement representation of x.
+func (x *Integer) Not() *Integer {
+       if x.sign {
+               // ^(-x) == ^(^(x-1)) == x-1
+               return MakeInt(false, x.mant.Sub(nat[1]));
+       }
+
+       // ^x == -x-1 == -(x+1)
+       return MakeInt(true, x.mant.Add(nat[1]));
+}
+
+
+// And returns the ``bitwise and'' x & y for the 2's-complement representation of x and y.
+//
+func (x *Integer) And(y *Integer) *Integer {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+                       return MakeInt(true, x.mant.Sub(nat[1]).Or(y.mant.Sub(nat[1])).Add(nat[1]));
+               }
+
+               // x & y == x & y
+               return MakeInt(false, x.mant.And(y.mant));
+       }
+
+       // x.sign != y.sign
+       if x.sign {
+               x, y = y, x;  // & is symmetric
+       }
+
+       // x & (-y) == x & ^(y-1) == x &^ (y-1)
+       return MakeInt(false, x.mant.AndNot(y.mant.Sub(nat[1])));
+}
+
+
+// AndNot returns the ``bitwise clear'' x &^ y for the 2's-complement representation of x and y.
+//
+func (x *Integer) AndNot(y *Integer) *Integer {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+                       return MakeInt(false, y.mant.Sub(nat[1]).AndNot(x.mant.Sub(nat[1])));
+               }
+
+               // x &^ y == x &^ y
+               return MakeInt(false, x.mant.AndNot(y.mant));
+       }
+
+       if x.sign {
+               // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+               return MakeInt(true, x.mant.Sub(nat[1]).Or(y.mant).Add(nat[1]));
+       }
+
+       // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+       return MakeInt(false, x.mant.And(y.mant.Sub(nat[1])));
+}
+
+
+// Or returns the ``bitwise or'' x | y for the 2's-complement representation of x and y.
+//
+func (x *Integer) Or(y *Integer) *Integer {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+                       return MakeInt(true, x.mant.Sub(nat[1]).And(y.mant.Sub(nat[1])).Add(nat[1]));
+               }
+
+               // x | y == x | y
+               return MakeInt(false, x.mant.Or(y.mant));
+       }
+
+       // x.sign != y.sign
+       if x.sign {
+               x, y = y, x;  // | or symmetric
+       }
+
+       // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+       return MakeInt(true, y.mant.Sub(nat[1]).AndNot(x.mant).Add(nat[1]));
+}
+
+
+// Xor returns the ``bitwise xor'' x | y for the 2's-complement representation of x and y.
+//
+func (x *Integer) Xor(y *Integer) *Integer {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+                       return MakeInt(false, x.mant.Sub(nat[1]).Xor(y.mant.Sub(nat[1])));
+               }
+
+               // x ^ y == x ^ y
+               return MakeInt(false, x.mant.Xor(y.mant));
+       }
+
+       // x.sign != y.sign
+       if x.sign {
+               x, y = y, x;  // ^ is symmetric
+       }
+
+       // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+       return MakeInt(true, x.mant.Xor(y.mant.Sub(nat[1])).Add(nat[1]));
+}
+
+
+// Cmp compares x and y. The result is an int value that is
+//
+//   <  0 if x <  y
+//   == 0 if x == y
+//   >  0 if x >  y
+//
+func (x *Integer) Cmp(y *Integer) int {
+       // x cmp y == x cmp y
+       // x cmp (-y) == x
+       // (-x) cmp y == y
+       // (-x) cmp (-y) == -(x cmp y)
+       var r int;
+       switch {
+       case x.sign == y.sign:
+               r = x.mant.Cmp(y.mant);
+               if x.sign {
+                       r = -r;
+               }
+       case x.sign: r = -1;
+       case y.sign: r = 1;
+       }
+       return r;
+}
+
+
+// ToString converts x to a string for a given base, with 2 <= base <= 16.
+//
+func (x *Integer) ToString(base uint) string {
+       if x.mant.IsZero() {
+               return "0";
+       }
+       var s string;
+       if x.sign {
+               s = "-";
+       }
+       return s + x.mant.ToString(base);
+}
+
+
+// String converts x to its decimal string representation.
+// x.String() is the same as x.ToString(10).
+//
+func (x *Integer) String() string {
+       return x.ToString(10);
+}
+
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
+//
+func (x *Integer) Format(h fmt.State, c int) {
+       fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
+}
+
+
+// IntFromString returns the integer corresponding to the
+// longest possible prefix of s representing an integer in a
+// given conversion base, the actual conversion base used, and
+// the prefix length. The syntax of integers follows the syntax
+// of signed integer literals in Go.
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
+// ``0'' prefix selects base 8. Otherwise the selected base is 10.
+//
+func IntFromString(s string, base uint) (*Integer, uint, int) {
+       // skip sign, if any
+       i0 := 0;
+       if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
+               i0 = 1;
+       }
+
+       mant, base, slen := NatFromString(s[i0 : len(s)], base);
+
+       return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen;
+}
diff --git a/src/pkg/bignum/rational.go b/src/pkg/bignum/rational.go
new file mode 100644 (file)
index 0000000..c00022b
--- /dev/null
@@ -0,0 +1,224 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rational numbers
+
+package bignum
+
+import "bignum"
+import "fmt"
+
+
+// Rational represents a quotient a/b of arbitrary precision.
+//
+type Rational struct {
+       a *Integer;  // numerator
+       b Natural;  // denominator
+}
+
+
+// MakeRat makes a rational number given a numerator a and a denominator b.
+//
+func MakeRat(a *Integer, b Natural) *Rational {
+       f := a.mant.Gcd(b);  // f > 0
+       if f.Cmp(nat[1]) != 0 {
+               a = MakeInt(a.sign, a.mant.Div(f));
+               b = b.Div(f);
+       }
+       return &Rational{a, b};
+}
+
+
+// Rat creates a small rational number with value a0/b0.
+//
+func Rat(a0 int64, b0 int64) *Rational {
+       a, b := Int(a0), Int(b0);
+       if b.sign {
+               a = a.Neg();
+       }
+       return MakeRat(a, b.mant);
+}
+
+
+// Value returns the numerator and denominator of x.
+//
+func (x *Rational) Value() (numerator *Integer, denominator Natural) {
+       return x.a, x.b;
+}
+
+
+// Predicates
+
+// IsZero returns true iff x == 0.
+//
+func (x *Rational) IsZero() bool {
+       return x.a.IsZero();
+}
+
+
+// IsNeg returns true iff x < 0.
+//
+func (x *Rational) IsNeg() bool {
+       return x.a.IsNeg();
+}
+
+
+// IsPos returns true iff x > 0.
+//
+func (x *Rational) IsPos() bool {
+       return x.a.IsPos();
+}
+
+
+// IsInt returns true iff x can be written with a denominator 1
+// in the form x == x'/1; i.e., if x is an integer value.
+//
+func (x *Rational) IsInt() bool {
+       return x.b.Cmp(nat[1]) == 0;
+}
+
+
+// Operations
+
+// Neg returns the negated value of x.
+//
+func (x *Rational) Neg() *Rational {
+       return MakeRat(x.a.Neg(), x.b);
+}
+
+
+// Add returns the sum x + y.
+//
+func (x *Rational) Add(y *Rational) *Rational {
+       return MakeRat((x.a.MulNat(y.b)).Add(y.a.MulNat(x.b)), x.b.Mul(y.b));
+}
+
+
+// Sub returns the difference x - y.
+//
+func (x *Rational) Sub(y *Rational) *Rational {
+       return MakeRat((x.a.MulNat(y.b)).Sub(y.a.MulNat(x.b)), x.b.Mul(y.b));
+}
+
+
+// Mul returns the product x * y.
+//
+func (x *Rational) Mul(y *Rational) *Rational {
+       return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b));
+}
+
+
+// Quo returns the quotient x / y for y != 0.
+// If y == 0, a division-by-zero run-time error occurs.
+//
+func (x *Rational) Quo(y *Rational) *Rational {
+       a := x.a.MulNat(y.b);
+       b := y.a.MulNat(x.b);
+       if b.IsNeg() {
+               a = a.Neg();
+       }
+       return MakeRat(a, b.mant);
+}
+
+
+// Cmp compares x and y. The result is an int value
+//
+//   <  0 if x <  y
+//   == 0 if x == y
+//   >  0 if x >  y
+//
+func (x *Rational) Cmp(y *Rational) int {
+       return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b));
+}
+
+
+// ToString converts x to a string for a given base, with 2 <= base <= 16.
+// The string representation is of the form "n" if x is an integer; otherwise
+// it is of form "n/d".
+//
+func (x *Rational) ToString(base uint) string {
+       s := x.a.ToString(base);
+       if !x.IsInt() {
+               s += "/" + x.b.ToString(base);
+       }
+       return s;
+}
+
+
+// String converts x to its decimal string representation.
+// x.String() is the same as x.ToString(10).
+//
+func (x *Rational) String() string {
+       return x.ToString(10);
+}
+
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
+//
+func (x *Rational) Format(h fmt.State, c int) {
+       fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
+}
+
+
+// RatFromString returns the rational number corresponding to the
+// longest possible prefix of s representing a rational number in a
+// given conversion base, the actual conversion base used, and the
+// prefix length. The syntax of a rational number is:
+//
+//     rational = mantissa [exponent] .
+//     mantissa = integer ('/' natural | '.' natural) .
+//     exponent = ('e'|'E') integer .
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base for the mantissa. A prefix of ``0x'' or ``0X'' selects
+// base 16; the ``0'' prefix selects base 8. Otherwise the selected base is 10.
+// If the mantissa is represented via a division, both the numerator and
+// denominator may have different base prefixes; in that case the base of
+// of the numerator is returned. If the mantissa contains a decimal point,
+// the base for the fractional part is the same as for the part before the
+// decimal point and the fractional part does not accept a base prefix.
+// The base for the exponent is always 10. 
+//
+func RatFromString(s string, base uint) (*Rational, uint, int) {
+       // read numerator
+       a, abase, alen := IntFromString(s, base);
+       b := nat[1];
+
+       // read denominator or fraction, if any
+       var blen int;
+       if alen < len(s) {
+               ch := s[alen];
+               if ch == '/' {
+                       alen++;
+                       b, base, blen = NatFromString(s[alen : len(s)], base);
+               } else if ch == '.' {
+                       alen++;
+                       b, base, blen = NatFromString(s[alen : len(s)], abase);
+                       assert(base == abase);
+                       f := Nat(uint64(base)).Pow(uint(blen));
+                       a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
+                       b = f;
+               }
+       }
+
+       // read exponent, if any
+       rlen := alen + blen;
+       if rlen < len(s) {
+               ch := s[rlen];
+               if ch == 'e' || ch == 'E' {
+                       rlen++;
+                       e, _, elen := IntFromString(s[rlen : len(s)], 10);
+                       rlen += elen;
+                       m := nat[10].Pow(uint(e.mant.Value()));
+                       if e.sign {
+                               b = b.Mul(m);
+                       } else {
+                               a = a.MulNat(m);
+                       }
+               }
+       }
+
+       return MakeRat(a, b), base, rlen;
+}