diff --git a/src/lib/bignum.go b/src/lib/bignum.go index 078374ad7e5..e122a2cace1 100755 --- a/src/lib/bignum.go +++ b/src/lib/bignum.go @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package bignum - // A package for arbitrary precision arithmethic. // It implements the following numeric types: // -// - Natural unsigned integer numbers -// - Integer signed integer numbers +// - Natural unsigned integers +// - Integer signed integers // - Rational rational numbers +// +package bignum import "fmt" @@ -21,13 +21,13 @@ import "fmt" // // x = x[n-1]*B^(n-1) + x[n-2]*B^(n-2) + ... + x[1]*B + x[0] // -// with 0 <= x[i] < B and 0 <= i < n is stored in an array of length n, -// with the digits x[i] as the array elements. +// with 0 <= x[i] < B and 0 <= i < n is stored in a slice of length n, +// with the digits x[i] as the slice elements. // -// A natural number is normalized if the array contains no leading 0 digits. -// During arithmetic operations, denormalized values may occur which are +// A natural number is normalized if the slice contains no leading 0 digits. +// During arithmetic operations, denormalized values may occur but are // always normalized before returning the final result. The normalized -// representation of 0 is the empty array (length = 0). +// representation of 0 is the empty slice (length = 0). // // The operations for all other numeric types are implemented on top of // the operations for natural numbers. @@ -42,7 +42,7 @@ import "fmt" // arithmetic. This makes addition, subtraction, and conversion routines // twice as fast. It requires a "buffer" of 4 bits per operand digit. // That is, the size of B must be 4 bits smaller then the size of the -// type (Digit) in which these operations are performed. Having this +// type (digit) in which these operations are performed. Having this // buffer also allows for trivial (single-bit) carry computation in // addition and subtraction (optimization suggested by Ken Thompson). // @@ -53,17 +53,16 @@ import "fmt" // in bits must be even. type ( - Digit uint64; - Digit2 uint32; // half-digits for division + digit uint64; + digit2 uint32; // half-digits for division ) -const _LogW = 64; -const _LogH = 4; // bits for a hex digit (= "small" number) -const _LogB = _LogW - _LogH; // largest bit-width available - - const ( + _LogW = 64; + _LogH = 4; // bits for a hex digit (= "small" number) + _LogB = _LogW - _LogH; // largest bit-width available + // half-digits _W2 = _LogB / 2; // width _B2 = 1 << _W2; // base @@ -86,12 +85,13 @@ func assert(p bool) { } -func isSmall(x Digit) bool { +func isSmall(x digit) bool { return x < 1<<_LogH; } -func Dump(x []Digit) { +// For debugging. +func dump(x []digit) { print("[", len(x), "]"); for i := len(x) - 1; i >= 0; i-- { print(" ", x[i]); @@ -102,16 +102,10 @@ func Dump(x []Digit) { // ---------------------------------------------------------------------------- // Natural numbers -// -// Naming conventions -// -// c carry -// x, y operands -// z result -// n, m len(x), len(y) - -type Natural []Digit; +// Natural represents an unsigned integer value of arbitrary precision. +// +type Natural []digit; var ( natZero Natural = Natural{}; @@ -121,8 +115,10 @@ var ( ) -// Creation - +// Nat creates a "small" natural number with value x. +// Implementation restriction: At the moment, only values +// x < (1<<60) are supported. +// func Nat(x uint) Natural { switch x { case 0: return natZero; @@ -130,24 +126,40 @@ func Nat(x uint) Natural { case 2: return natTwo; case 10: return natTen; } - assert(Digit(x) < _B); - return Natural{Digit(x)}; + assert(digit(x) < _B); + return Natural{digit(x)}; } -// Predicates +// IsEven returns true iff x is divisible by 2. +// +func (x Natural) IsEven() bool { + return len(x) == 0 || x[0]&1 == 0; +} + +// IsOdd returns true iff x is not divisible by 2. +// func (x Natural) IsOdd() bool { return len(x) > 0 && x[0]&1 != 0; } +// IsZero returns true iff x == 0. +// func (x Natural) IsZero() bool { return len(x) == 0; } // Operations +// +// Naming conventions +// +// c carry +// x, y operands +// z result +// n, m len(x), len(y) func normalize(x Natural) Natural { n := len(x); @@ -159,6 +171,8 @@ func normalize(x Natural) Natural { } +// Add returns the sum x + y. +// func (x Natural) Add(y Natural) Natural { n := len(x); m := len(y); @@ -166,7 +180,7 @@ func (x Natural) Add(y Natural) Natural { return y.Add(x); } - c := Digit(0); + c := digit(0); z := make(Natural, n + 1); i := 0; for i < m { @@ -188,6 +202,9 @@ func (x Natural) Add(y Natural) Natural { } +// Sub returns the difference x - y for x >= y. +// If x < y, an underflow run-time error occurs (use Cmp to test if x >= y). +// func (x Natural) Sub(y Natural) Natural { n := len(x); m := len(y); @@ -195,17 +212,17 @@ func (x Natural) Sub(y Natural) Natural { panic("underflow") } - c := Digit(0); + c := digit(0); z := make(Natural, n); i := 0; for i < m { t := c + x[i] - y[i]; - c, z[i] = Digit(int64(t)>>_W), t&_M; // requires arithmetic shift! + c, z[i] = digit(int64(t)>>_W), t&_M; // requires arithmetic shift! i++; } for i < n { t := c + x[i]; - c, z[i] = Digit(int64(t)>>_W), t&_M; // requires arithmetic shift! + c, z[i] = digit(int64(t)>>_W), t&_M; // requires arithmetic shift! i++; } for i > 0 && z[i - 1] == 0 { // normalize @@ -217,7 +234,8 @@ func (x Natural) Sub(y Natural) Natural { // Returns c = x*y div B, z = x*y mod B. -func mul11(x, y Digit) (Digit, Digit) { +// +func mul11(x, y digit) (digit, digit) { // Split x and y into 2 sub-digits each, // multiply the digits separately while avoiding overflow, // and return the product as two separate digits. @@ -250,6 +268,8 @@ func mul11(x, y Digit) (Digit, Digit) { } +// Mul returns the product x * y. +// func (x Natural) Mul(y Natural) Natural { n := len(x); m := len(y); @@ -258,7 +278,7 @@ func (x Natural) Mul(y Natural) Natural { for j := 0; j < m; j++ { d := y[j]; if d != 0 { - c := Digit(0); + c := digit(0); for i := 0; i < n; i++ { // z[i+j] += c + x[i]*d; z1, z0 := mul11(x[i], d); @@ -274,18 +294,18 @@ func (x Natural) Mul(y Natural) Natural { } -// DivMod needs multi-precision division which is not available if Digit +// DivMod needs multi-precision division, which is not available if digit // is already using the largest uint size. Instead, unpack each operand -// into operands with twice as many digits of half the size (Digit2), do +// into operands with twice as many digits of half the size (digit2), do // DivMod, and then pack the results again. -func unpack(x Natural) []Digit2 { +func unpack(x Natural) []digit2 { n := len(x); - z := make([]Digit2, n*2 + 1); // add space for extra digit (used by DivMod) + z := make([]digit2, n*2 + 1); // add space for extra digit (used by DivMod) for i := 0; i < n; i++ { t := x[i]; - z[i*2] = Digit2(t & _M2); - z[i*2 + 1] = Digit2(t >> _W2 & _M2); + z[i*2] = digit2(t & _M2); + z[i*2 + 1] = digit2(t >> _W2 & _M2); } // normalize result @@ -295,42 +315,42 @@ func unpack(x Natural) []Digit2 { } -func pack(x []Digit2) Natural { +func pack(x []digit2) Natural { n := (len(x) + 1) / 2; z := make(Natural, n); if len(x) & 1 == 1 { // handle odd len(x) n--; - z[n] = Digit(x[n*2]); + z[n] = digit(x[n*2]); } for i := 0; i < n; i++ { - z[i] = Digit(x[i*2 + 1]) << _W2 | Digit(x[i*2]); + z[i] = digit(x[i*2 + 1]) << _W2 | digit(x[i*2]); } return normalize(z); } -func mul1(z, x []Digit2, y Digit2) Digit2 { +func mul1(z, x []digit2, y digit2) digit2 { n := len(x); - c := Digit(0); - f := Digit(y); + c := digit(0); + f := digit(y); for i := 0; i < n; i++ { - t := c + Digit(x[i])*f; - c, z[i] = t>>_W2, Digit2(t&_M2); + t := c + digit(x[i])*f; + c, z[i] = t>>_W2, digit2(t&_M2); } - return Digit2(c); + return digit2(c); } -func div1(z, x []Digit2, y Digit2) Digit2 { +func div1(z, x []digit2, y digit2) digit2 { n := len(x); - c := Digit(0); - d := Digit(y); + c := digit(0); + d := digit(y); for i := n-1; i >= 0; i-- { - t := c*_B2 + Digit(x[i]); - c, z[i] = t%d, Digit2(t/d); + t := c*_B2 + digit(x[i]); + c, z[i] = t%d, digit2(t/d); } - return Digit2(c); + return digit2(c); } @@ -354,7 +374,7 @@ func div1(z, x []Digit2, y Digit2) Digit2 { // minefield. "Software - Practice and Experience 24", (June 1994), // 579-601. John Wiley & Sons, Ltd. -func divmod(x, y []Digit2) ([]Digit2, []Digit2) { +func divmod(x, y []digit2) ([]digit2, []digit2) { n := len(x); m := len(y); if m == 0 { @@ -382,21 +402,21 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) { // TODO Instead of multiplying, it would be sufficient to // shift y such that the normalization condition is // satisfied (as done in "Hacker's Delight"). - f := _B2 / (Digit(y[m-1]) + 1); + f := _B2 / (digit(y[m-1]) + 1); if f != 1 { - mul1(x, x, Digit2(f)); - mul1(y, y, Digit2(f)); + mul1(x, x, digit2(f)); + 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); + 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]); + var q digit; + { x0, x1, x2 := digit(x[k]), digit(x[k-1]), digit(x[k-2]); if x0 != y1 { q = (x0<<_W2 + x1)/y1; } else { @@ -408,31 +428,31 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) { } // subtract y*q - c := Digit(0); + 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! + 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 { + if c + digit(x[k]) != 0 { // add y - c := Digit(0); + c := digit(0); for j := 0; j < m; j++ { - t := c + Digit(x[i+j]) + Digit(y[j]); - c, x[i+j] = t >> _W2, Digit2(t & _M2) + t := c + digit(x[i+j]) + digit(y[j]); + c, x[i+j] = t >> _W2, digit2(t & _M2) } - assert(c + Digit(x[k]) == 0); + assert(c + digit(x[k]) == 0); // correct trial digit q--; } - x[k] = Digit2(q); + x[k] = digit2(q); } // undo normalization for remainder if f != 1 { - c := div1(x[0 : m], x[0 : m], Digit2(f)); + c := div1(x[0 : m], x[0 : m], digit2(f)); assert(c == 0); } } @@ -441,28 +461,39 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) { } +// Div returns the quotient q = x / y for y > 0, +// with x = y*q + r and 0 <= r < y. +// If y == 0, a division-by-zero run-time error occurs. +// func (x Natural) Div(y Natural) Natural { q, r := divmod(unpack(x), unpack(y)); return pack(q); } +// Mod returns the modulus r of the division x / y for y > 0, +// with x = y*q + r and 0 <= r < y. +// If y == 0, a division-by-zero run-time error occurs. +// func (x Natural) Mod(y Natural) Natural { q, r := divmod(unpack(x), unpack(y)); return pack(r); } +// DivMod returns the pair (x.Div(y), x.Mod(y)) for y > 0. +// If y == 0, a division-by-zero run-time error occurs. +// func (x Natural) DivMod(y Natural) (Natural, Natural) { q, r := divmod(unpack(x), unpack(y)); return pack(q), pack(r); } -func shl(z, x []Digit, s uint) Digit { +func shl(z, x []digit, s uint) digit { assert(s <= _W); n := len(x); - c := Digit(0); + c := digit(0); for i := 0; i < n; i++ { c, z[i] = x[i] >> (_W-s), x[i] << s & _M | c; } @@ -470,6 +501,8 @@ func shl(z, x []Digit, s uint) Digit { } +// Shl implements "shift left" x << s. It returns x * 2^s. +// func (x Natural) Shl(s uint) Natural { n := uint(len(x)); m := n + s/_W; @@ -481,10 +514,10 @@ func (x Natural) Shl(s uint) Natural { } -func shr(z, x []Digit, s uint) Digit { +func shr(z, x []digit, s uint) digit { assert(s <= _W); n := len(x); - c := Digit(0); + c := digit(0); for i := n - 1; i >= 0; i-- { c, z[i] = x[i] << (_W-s) & _M, x[i] >> s | c; } @@ -492,6 +525,8 @@ func shr(z, x []Digit, s uint) Digit { } +// Shr implements "shift right" x >> s. It returns x / 2^s. +// func (x Natural) Shr(s uint) Natural { n := uint(len(x)); m := n - s/_W; @@ -506,6 +541,8 @@ func (x Natural) Shr(s uint) Natural { } +// And returns the "bitwise and" x & y for the binary representation of x and y. +// func (x Natural) And(y Natural) Natural { n := len(x); m := len(y); @@ -523,13 +560,15 @@ func (x Natural) And(y Natural) Natural { } -func copy(z, x []Digit) { +func copy(z, x []digit) { for i, e := range x { z[i] = e } } +// Or returns the "bitwise or" x | y for the binary representation of x and y. +// func (x Natural) Or(y Natural) Natural { n := len(x); m := len(y); @@ -547,6 +586,8 @@ func (x Natural) Or(y Natural) Natural { } +// Xor returns the "bitwise exclusive or" x ^ y for the binary representation of x and y. +// func (x Natural) Xor(y Natural) Natural { n := len(x); m := len(y); @@ -564,6 +605,12 @@ func (x Natural) Xor(y Natural) Natural { } +// 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 Natural) Cmp(y Natural) int { n := len(x); m := len(y); @@ -585,7 +632,7 @@ func (x Natural) Cmp(y Natural) int { } -func log2(x Digit) uint { +func log2(x digit) uint { assert(x > 0); n := uint(0); for x > 0 { @@ -596,6 +643,10 @@ func log2(x Digit) uint { } +// Log2 computes the binary logarithm of x for x > 0. +// The result is the integer n for which 2^n <= x < 2^(n+1). +// If x == 0 a run-time error occurs. +// func (x Natural) Log2() uint { n := len(x); if n > 0 { @@ -607,10 +658,11 @@ func (x Natural) Log2() uint { // Computes x = x div d in place (modifies x) for "small" d's. // Returns updated x and x mod d. -func divmod1(x Natural, d Digit) (Natural, Digit) { +// +func divmod1(x Natural, d digit) (Natural, digit) { assert(0 < d && isSmall(d - 1)); - c := Digit(0); + c := digit(0); for i := len(x) - 1; i >= 0; i-- { t := c<<_W + x[i]; c, x[i] = t%d, t/d; @@ -620,6 +672,8 @@ func divmod1(x Natural, d Digit) (Natural, Digit) { } +// ToString converts x to a string for a given base, with 2 <= base <= 16. +// func (x Natural) ToString(base uint) string { if len(x) == 0 { return "0"; @@ -627,7 +681,7 @@ func (x Natural) ToString(base uint) string { // allocate buffer for conversion assert(2 <= base && base <= 16); - n := (x.Log2() + 1) / log2(Digit(base)) + 1; // +1: round up + n := (x.Log2() + 1) / log2(digit(base)) + 1; // +1: round up s := make([]byte, n); // don't destroy x @@ -638,8 +692,8 @@ func (x Natural) ToString(base uint) string { i := n; for !t.IsZero() { i--; - var d Digit; - t, d = divmod1(t, Digit(base)); + var d digit; + t, d = divmod1(t, digit(base)); s[i] = "0123456789abcdef"[d]; }; @@ -647,6 +701,9 @@ func (x Natural) ToString(base uint) string { } +// String converts x to its decimal string representation. +// (x.String is the same as x.ToString(10)). +// func (x Natural) String() string { return x.ToString(10); } @@ -662,6 +719,9 @@ func fmtbase(c int) uint { } +// Format is a support routine for fmt.Formatter. It accepts +// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). +// func (x Natural) Format(h fmt.Formatter, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); } @@ -679,7 +739,8 @@ func hexvalue(ch byte) uint { // Computes x = x*d + c for "small" d's. -func muladd1(x Natural, d, c Digit) Natural { +// +func muladd1(x Natural, d, c digit) Natural { assert(isSmall(d-1) && isSmall(c)); n := len(x); z := make(Natural, n + 1); @@ -694,8 +755,17 @@ func muladd1(x Natural, d, c Digit) Natural { } -// Determines base (octal, decimal, hexadecimal) if base == 0. -// Returns the number and base. +// NatFromString returns the natural number corresponding to the +// longest possible prefix of s representing a natural number in a +// given conversion base. +// +// 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. +// +// If a non-nil slen argument is provided, *slen is set to the length +// of the string prefix converted. +// func NatFromString(s string, base uint, slen *int) (Natural, uint) { // determine base if necessary i, n := 0, len(s); @@ -716,7 +786,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) { for ; i < n; i++ { d := hexvalue(s[i]); if d < base { - x = muladd1(x, Digit(base), Digit(d)); + x = muladd1(x, digit(base), digit(d)); } else { break; } @@ -733,7 +803,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) { // Natural number functions -func pop1(x Digit) uint { +func pop1(x digit) uint { n := uint(0); for x != 0 { x &= x-1; @@ -743,6 +813,10 @@ func pop1(x Digit) uint { } +// Pop computes the "population count" of x. +// The result is the number of set bits (i.e., "1" digits) +// in the binary representation of x. +// func (x Natural) Pop() uint { n := uint(0); for i := len(x) - 1; i >= 0; i-- { @@ -752,6 +826,8 @@ func (x Natural) Pop() uint { } +// Pow computes x to the power of n. +// func (xp Natural) Pow(n uint) Natural { z := Nat(1); x := xp; @@ -766,6 +842,9 @@ func (xp Natural) Pow(n uint) Natural { } +// MulRange computes the product of all the unsigned integers +// in the range [a, b] inclusively. +// func MulRange(a, b uint) Natural { switch { case a > b: return Nat(1); @@ -778,6 +857,8 @@ func MulRange(a, b uint) Natural { } +// Fact computes the factorial of n (Fact(n) == MulRange(2, n)). +// func Fact(n uint) Natural { // Using MulRange() instead of the basic for-loop // lead to faster factorial computation. @@ -785,18 +866,22 @@ func Fact(n uint) Natural { } +// Binomial computes the binomial coefficient of (n, k). +// func Binomial(n, k uint) Natural { return MulRange(n-k+1, n).Div(MulRange(1, k)); } -func (xp Natural) Gcd(y Natural) Natural { +// Gcd computes the gcd of x and y. +// +func (x Natural) Gcd(y Natural) Natural { // Euclidean algorithm. - x := xp; - for !y.IsZero() { - x, y = y, x.Mod(y); + a, b := x, y; + for !b.IsZero() { + a, b = b, a.Mod(b); } - return x; + return a; } @@ -806,14 +891,18 @@ func (xp Natural) Gcd(y Natural) Natural { // 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; } -// Creation - +// 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 @@ -822,6 +911,10 @@ func MakeInt(sign bool, mant Natural) *Integer { } +// Int creates a "small" integer with value x. +// Implementation restriction: At the moment, only values +// with an absolute value |x| < (1<<60) are supported. +// func Int(x int) *Integer { sign := false; var ux uint; @@ -843,21 +936,36 @@ func Int(x int) *Integer { // 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() } @@ -865,11 +973,15 @@ func (x *Integer) IsPos() bool { // 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 { @@ -892,6 +1004,8 @@ func (x *Integer) Add(y *Integer) *Integer { } +// Sub returns the difference x - y. +// func (x *Integer) Sub(y *Integer) *Integer { var z *Integer; if x.sign != y.sign { @@ -914,6 +1028,8 @@ func (x *Integer) Sub(y *Integer) *Integer { } +// Mul returns the product x * y. +// func (x *Integer) Mul(y *Integer) *Integer { // x * y == x * y // x * (-y) == -(x * y) @@ -923,6 +1039,8 @@ func (x *Integer) Mul(y *Integer) *Integer { } +// 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) @@ -930,13 +1048,16 @@ func (x *Integer) MulNat(y Natural) *Integer { } +// 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". ) - +// (Daan Leijen, "Division and Modulus for Computer Scientists".) +// func (x *Integer) Quo(y *Integer) *Integer { // x / y == x / y // x / (-y) == -(x / y) @@ -946,6 +1067,11 @@ func (x *Integer) Quo(y *Integer) *Integer { } +// 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 @@ -955,23 +1081,28 @@ func (x *Integer) Rem(y *Integer) *Integer { } +// 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: // -// d = x.Div(y) -// m = x.Mod(y) with: 0 <= m < |d| and: y = x*d + m +// 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.) // -// ( 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() { @@ -985,6 +1116,10 @@ func (x *Integer) Div(y *Integer) *Integer { } +// 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() { @@ -998,6 +1133,8 @@ func (x *Integer) Mod(y *Integer) *Integer { } +// 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() { @@ -1013,53 +1150,73 @@ func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) { } +// 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)); } +// Shr implements "shift right" x >> s. It returns x / 2^s. +// Implementation restriction: Shl is not yet implemented for negative x. +// func (x *Integer) Shr(s uint) *Integer { z := MakeInt(x.sign, x.mant.Shr(s)); if x.IsNeg() { - panic("UNIMPLEMENTED Integer.Shr() of negative values"); + panic("UNIMPLEMENTED Integer.Shr of negative values"); } return z; } +// And returns the "bitwise and" x & y for the binary representation of x and y. +// Implementation restriction: And is not implemented for negative x. +// func (x *Integer) And(y *Integer) *Integer { var z *Integer; if !x.sign && !y.sign { z = MakeInt(false, x.mant.And(y.mant)); } else { - panic("UNIMPLEMENTED Integer.And() of negative values"); + panic("UNIMPLEMENTED Integer.And of negative values"); } return z; } +// Or returns the "bitwise or" x | y for the binary representation of x and y. +// Implementation restriction: Or is not implemented for negative x. +// func (x *Integer) Or(y *Integer) *Integer { var z *Integer; if !x.sign && !y.sign { z = MakeInt(false, x.mant.Or(y.mant)); } else { - panic("UNIMPLEMENTED Integer.Or() of negative values"); + panic("UNIMPLEMENTED Integer.Or of negative values"); } return z; } +// Xor returns the "bitwise xor" x | y for the binary representation of x and y. +// Implementation restriction: Xor is not implemented for negative integers. +// func (x *Integer) Xor(y *Integer) *Integer { var z *Integer; if !x.sign && !y.sign { z = MakeInt(false, x.mant.Xor(y.mant)); } else { - panic("UNIMPLEMENTED Integer.Xor() of negative values"); + panic("UNIMPLEMENTED Integer.Xor of negative values"); } return z; } +// 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 @@ -1079,6 +1236,8 @@ func (x *Integer) Cmp(y *Integer) int { } +// 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"; @@ -1091,18 +1250,33 @@ func (x *Integer) ToString(base uint) string { } +// 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.Formatter, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); } -// Determines base (octal, decimal, hexadecimal) if base == 0. -// Returns the number and base. +// IntFromString returns the integer corresponding to the +// longest possible prefix of s representing an integer in a +// given conversion base. +// +// 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. +// +// If a non-nil slen argument is provided, *slen is set to the length +// of the string prefix converted. +// func IntFromString(s string, base uint, slen *int) (*Integer, uint) { // get sign, if any sign := false; @@ -1126,14 +1300,16 @@ func IntFromString(s string, base uint, slen *int) (*Integer, uint) { // ---------------------------------------------------------------------------- // Rational numbers +// Rational represents a quotient a/b of arbitrary precision. +// type Rational struct { a *Integer; // numerator b Natural; // denominator } -// Creation - +// 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 { @@ -1144,6 +1320,10 @@ func MakeRat(a *Integer, b Natural) *Rational { } +// Rat creates a "small" rational number with value a0/b0. +// Implementation restriction: At the moment, only values a0, b0 +// with an absolute value |a0|, |b0| < (1<<60) are supported. +// func Rat(a0 int, b0 int) *Rational { a, b := Int(a0), Int(b0); if b.sign { @@ -1155,21 +1335,30 @@ func Rat(a0 int, b0 int) *Rational { // 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; } @@ -1177,26 +1366,37 @@ func (x *Rational) IsInt() bool { // 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); @@ -1207,11 +1407,20 @@ func (x *Rational) Quo(y *Rational) *Rational { } +// 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 "numerator/denominator". +// func (x *Rational) ToString(base uint) string { s := x.a.ToString(base); if !x.IsInt() { @@ -1221,18 +1430,33 @@ func (x *Rational) ToString(base uint) string { } +// 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.Formatter, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); } -// Determines base (octal, decimal, hexadecimal) if base == 0. -// Returns the number and base of the nominator. +// RatFromString returns the rational number corresponding to the +// longest possible prefix of s representing a rational number in a +// given conversion base. +// +// 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. +// +// If a non-nil slen argument is provided, *slen is set to the length +// of the string prefix converted. +// func RatFromString(s string, base uint, slen *int) (*Rational, uint) { // read nominator var alen, blen int;