From: Robert Griesemer Date: Tue, 21 Jul 2009 21:28:59 +0000 (-0700) Subject: - split bignum package into 3 files X-Git-Tag: weekly.2009-11-06~1083 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e62dd7bce93549ddf3d3991409d51a26c9f169b9;p=gostls13.git - split bignum package into 3 files - 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 --- diff --git a/src/pkg/bignum/Makefile b/src/pkg/bignum/Makefile index 098b909753..12d1f3193d 100644 --- a/src/pkg/bignum/Makefile +++ b/src/pkg/bignum/Makefile @@ -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 diff --git a/src/pkg/bignum/bignum.go b/src/pkg/bignum/bignum.go index 91a207dd41..71bf66d761 100755 --- a/src/pkg/bignum/bignum.go +++ b/src/pkg/bignum/bignum.go @@ -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; -} diff --git a/src/pkg/bignum/bignum_test.go b/src/pkg/bignum/bignum_test.go index d07446bb46..d691da2327 100644 --- a/src/pkg/bignum/bignum_test.go +++ b/src/pkg/bignum/bignum_test.go @@ -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 index 0000000000..f3c111d0b4 --- /dev/null +++ b/src/pkg/bignum/integer.go @@ -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 index 0000000000..c00022b296 --- /dev/null +++ b/src/pkg/bignum/rational.go @@ -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; +}