Commit 3ae849d4 authored by Robert Griesemer's avatar Robert Griesemer

- documentation for bignum package

- removed some constants from public interface

R=r
DELTA=375  (238 added, 14 deleted, 123 changed)
OCL=27636
CL=27668
parent 5689e647
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package bignum
// A package for arbitrary precision arithmethic. // A package for arbitrary precision arithmethic.
// It implements the following numeric types: // It implements the following numeric types:
// //
// - Natural unsigned integer numbers // - Natural unsigned integers
// - Integer signed integer numbers // - Integer signed integers
// - Rational rational numbers // - Rational rational numbers
//
package bignum
import "fmt" import "fmt"
...@@ -21,13 +21,13 @@ 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] // 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 0 <= x[i] < B and 0 <= i < n is stored in a slice of length n,
// with the digits x[i] as the array elements. // with the digits x[i] as the slice elements.
// //
// A natural number is normalized if the array contains no leading 0 digits. // A natural number is normalized if the slice contains no leading 0 digits.
// During arithmetic operations, denormalized values may occur which are // During arithmetic operations, denormalized values may occur but are
// always normalized before returning the final result. The normalized // 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 all other numeric types are implemented on top of
// the operations for natural numbers. // the operations for natural numbers.
...@@ -42,7 +42,7 @@ import "fmt" ...@@ -42,7 +42,7 @@ import "fmt"
// arithmetic. This makes addition, subtraction, and conversion routines // arithmetic. This makes addition, subtraction, and conversion routines
// twice as fast. It requires a "buffer" of 4 bits per operand digit. // 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 // 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 // buffer also allows for trivial (single-bit) carry computation in
// addition and subtraction (optimization suggested by Ken Thompson). // addition and subtraction (optimization suggested by Ken Thompson).
// //
...@@ -53,17 +53,16 @@ import "fmt" ...@@ -53,17 +53,16 @@ import "fmt"
// in bits must be even. // in bits must be even.
type ( type (
Digit uint64; digit uint64;
Digit2 uint32; // half-digits for division 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 ( const (
_LogW = 64;
_LogH = 4; // bits for a hex digit (= "small" number)
_LogB = _LogW - _LogH; // largest bit-width available
// half-digits // half-digits
_W2 = _LogB / 2; // width _W2 = _LogB / 2; // width
_B2 = 1 << _W2; // base _B2 = 1 << _W2; // base
...@@ -86,12 +85,13 @@ func assert(p bool) { ...@@ -86,12 +85,13 @@ func assert(p bool) {
} }
func isSmall(x Digit) bool { func isSmall(x digit) bool {
return x < 1<<_LogH; return x < 1<<_LogH;
} }
func Dump(x []Digit) { // For debugging.
func dump(x []digit) {
print("[", len(x), "]"); print("[", len(x), "]");
for i := len(x) - 1; i >= 0; i-- { for i := len(x) - 1; i >= 0; i-- {
print(" ", x[i]); print(" ", x[i]);
...@@ -102,16 +102,10 @@ func Dump(x []Digit) { ...@@ -102,16 +102,10 @@ func Dump(x []Digit) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Natural numbers // Natural numbers
//
// Naming conventions
//
// c carry
// x, y operands
// z result
// n, m len(x), len(y)
// Natural represents an unsigned integer value of arbitrary precision.
type Natural []Digit; //
type Natural []digit;
var ( var (
natZero Natural = Natural{}; natZero Natural = Natural{};
...@@ -121,8 +115,10 @@ var ( ...@@ -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 { func Nat(x uint) Natural {
switch x { switch x {
case 0: return natZero; case 0: return natZero;
...@@ -130,24 +126,40 @@ func Nat(x uint) Natural { ...@@ -130,24 +126,40 @@ func Nat(x uint) Natural {
case 2: return natTwo; case 2: return natTwo;
case 10: return natTen; case 10: return natTen;
} }
assert(Digit(x) < _B); assert(digit(x) < _B);
return Natural{Digit(x)}; 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 { func (x Natural) IsOdd() bool {
return len(x) > 0 && x[0]&1 != 0; return len(x) > 0 && x[0]&1 != 0;
} }
// IsZero returns true iff x == 0.
//
func (x Natural) IsZero() bool { func (x Natural) IsZero() bool {
return len(x) == 0; return len(x) == 0;
} }
// Operations // Operations
//
// Naming conventions
//
// c carry
// x, y operands
// z result
// n, m len(x), len(y)
func normalize(x Natural) Natural { func normalize(x Natural) Natural {
n := len(x); n := len(x);
...@@ -159,6 +171,8 @@ func normalize(x Natural) Natural { ...@@ -159,6 +171,8 @@ func normalize(x Natural) Natural {
} }
// Add returns the sum x + y.
//
func (x Natural) Add(y Natural) Natural { func (x Natural) Add(y Natural) Natural {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -166,7 +180,7 @@ func (x Natural) Add(y Natural) Natural { ...@@ -166,7 +180,7 @@ func (x Natural) Add(y Natural) Natural {
return y.Add(x); return y.Add(x);
} }
c := Digit(0); c := digit(0);
z := make(Natural, n + 1); z := make(Natural, n + 1);
i := 0; i := 0;
for i < m { for i < m {
...@@ -188,6 +202,9 @@ func (x Natural) Add(y Natural) Natural { ...@@ -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 { func (x Natural) Sub(y Natural) Natural {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -195,17 +212,17 @@ func (x Natural) Sub(y Natural) Natural { ...@@ -195,17 +212,17 @@ func (x Natural) Sub(y Natural) Natural {
panic("underflow") panic("underflow")
} }
c := Digit(0); c := digit(0);
z := make(Natural, n); z := make(Natural, n);
i := 0; i := 0;
for i < m { for i < m {
t := c + x[i] - y[i]; 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++; i++;
} }
for i < n { for i < n {
t := c + x[i]; 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++; i++;
} }
for i > 0 && z[i - 1] == 0 { // normalize for i > 0 && z[i - 1] == 0 { // normalize
...@@ -217,7 +234,8 @@ func (x Natural) Sub(y Natural) Natural { ...@@ -217,7 +234,8 @@ func (x Natural) Sub(y Natural) Natural {
// Returns c = x*y div B, z = x*y mod B. // 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, // Split x and y into 2 sub-digits each,
// multiply the digits separately while avoiding overflow, // multiply the digits separately while avoiding overflow,
// and return the product as two separate digits. // and return the product as two separate digits.
...@@ -250,6 +268,8 @@ func mul11(x, y Digit) (Digit, Digit) { ...@@ -250,6 +268,8 @@ func mul11(x, y Digit) (Digit, Digit) {
} }
// Mul returns the product x * y.
//
func (x Natural) Mul(y Natural) Natural { func (x Natural) Mul(y Natural) Natural {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -258,7 +278,7 @@ func (x Natural) Mul(y Natural) Natural { ...@@ -258,7 +278,7 @@ func (x Natural) Mul(y Natural) Natural {
for j := 0; j < m; j++ { for j := 0; j < m; j++ {
d := y[j]; d := y[j];
if d != 0 { if d != 0 {
c := Digit(0); c := digit(0);
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
// z[i+j] += c + x[i]*d; // z[i+j] += c + x[i]*d;
z1, z0 := mul11(x[i], d); z1, z0 := mul11(x[i], d);
...@@ -274,18 +294,18 @@ func (x Natural) Mul(y Natural) Natural { ...@@ -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 // 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. // DivMod, and then pack the results again.
func unpack(x Natural) []Digit2 { func unpack(x Natural) []digit2 {
n := len(x); 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++ { for i := 0; i < n; i++ {
t := x[i]; t := x[i];
z[i*2] = Digit2(t & _M2); z[i*2] = digit2(t & _M2);
z[i*2 + 1] = Digit2(t >> _W2 & _M2); z[i*2 + 1] = digit2(t >> _W2 & _M2);
} }
// normalize result // normalize result
...@@ -295,42 +315,42 @@ func unpack(x Natural) []Digit2 { ...@@ -295,42 +315,42 @@ func unpack(x Natural) []Digit2 {
} }
func pack(x []Digit2) Natural { func pack(x []digit2) Natural {
n := (len(x) + 1) / 2; n := (len(x) + 1) / 2;
z := make(Natural, n); z := make(Natural, n);
if len(x) & 1 == 1 { if len(x) & 1 == 1 {
// handle odd len(x) // handle odd len(x)
n--; n--;
z[n] = Digit(x[n*2]); z[n] = digit(x[n*2]);
} }
for i := 0; i < n; i++ { 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); return normalize(z);
} }
func mul1(z, x []Digit2, y Digit2) Digit2 { func mul1(z, x []digit2, y digit2) digit2 {
n := len(x); n := len(x);
c := Digit(0); c := digit(0);
f := Digit(y); f := digit(y);
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
t := c + Digit(x[i])*f; t := c + digit(x[i])*f;
c, z[i] = t>>_W2, Digit2(t&_M2); 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); n := len(x);
c := Digit(0); c := digit(0);
d := Digit(y); d := digit(y);
for i := n-1; i >= 0; i-- { for i := n-1; i >= 0; i-- {
t := c*_B2 + Digit(x[i]); t := c*_B2 + digit(x[i]);
c, z[i] = t%d, Digit2(t/d); 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 { ...@@ -354,7 +374,7 @@ func div1(z, x []Digit2, y Digit2) Digit2 {
// minefield. "Software - Practice and Experience 24", (June 1994), // minefield. "Software - Practice and Experience 24", (June 1994),
// 579-601. John Wiley & Sons, Ltd. // 579-601. John Wiley & Sons, Ltd.
func divmod(x, y []Digit2) ([]Digit2, []Digit2) { func divmod(x, y []digit2) ([]digit2, []digit2) {
n := len(x); n := len(x);
m := len(y); m := len(y);
if m == 0 { if m == 0 {
...@@ -382,21 +402,21 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) { ...@@ -382,21 +402,21 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) {
// TODO Instead of multiplying, it would be sufficient to // TODO Instead of multiplying, it would be sufficient to
// shift y such that the normalization condition is // shift y such that the normalization condition is
// satisfied (as done in "Hacker's Delight"). // satisfied (as done in "Hacker's Delight").
f := _B2 / (Digit(y[m-1]) + 1); f := _B2 / (digit(y[m-1]) + 1);
if f != 1 { if f != 1 {
mul1(x, x, Digit2(f)); mul1(x, x, digit2(f));
mul1(y, y, Digit2(f)); mul1(y, y, digit2(f));
} }
assert(_B2/2 <= y[m-1] && y[m-1] < _B2); // incorrect scaling assert(_B2/2 <= y[m-1] && y[m-1] < _B2); // incorrect scaling
y1, y2 := Digit(y[m-1]), Digit(y[m-2]); y1, y2 := digit(y[m-1]), digit(y[m-2]);
d2 := Digit(y1)<<_W2 + Digit(y2); d2 := digit(y1)<<_W2 + digit(y2);
for i := n-m; i >= 0; i-- { for i := n-m; i >= 0; i-- {
k := i+m; k := i+m;
// compute trial digit (Knuth) // compute trial digit (Knuth)
var q Digit; var q digit;
{ x0, x1, x2 := Digit(x[k]), Digit(x[k-1]), Digit(x[k-2]); { x0, x1, x2 := digit(x[k]), digit(x[k-1]), digit(x[k-2]);
if x0 != y1 { if x0 != y1 {
q = (x0<<_W2 + x1)/y1; q = (x0<<_W2 + x1)/y1;
} else { } else {
...@@ -408,31 +428,31 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) { ...@@ -408,31 +428,31 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) {
} }
// subtract y*q // subtract y*q
c := Digit(0); c := digit(0);
for j := 0; j < m; j++ { for j := 0; j < m; j++ {
t := c + Digit(x[i+j]) - Digit(y[j])*q; t := c + digit(x[i+j]) - digit(y[j])*q;
c, x[i+j] = Digit(int64(t) >> _W2), Digit2(t & _M2); // requires arithmetic shift! c, x[i+j] = digit(int64(t) >> _W2), digit2(t & _M2); // requires arithmetic shift!
} }
// correct if trial digit was too large // correct if trial digit was too large
if c + Digit(x[k]) != 0 { if c + digit(x[k]) != 0 {
// add y // add y
c := Digit(0); c := digit(0);
for j := 0; j < m; j++ { for j := 0; j < m; j++ {
t := c + Digit(x[i+j]) + Digit(y[j]); t := c + digit(x[i+j]) + digit(y[j]);
c, x[i+j] = t >> _W2, Digit2(t & _M2) c, x[i+j] = t >> _W2, digit2(t & _M2)
} }
assert(c + Digit(x[k]) == 0); assert(c + digit(x[k]) == 0);
// correct trial digit // correct trial digit
q--; q--;
} }
x[k] = Digit2(q); x[k] = digit2(q);
} }
// undo normalization for remainder // undo normalization for remainder
if f != 1 { 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); assert(c == 0);
} }
} }
...@@ -441,28 +461,39 @@ func divmod(x, y []Digit2) ([]Digit2, []Digit2) { ...@@ -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 { func (x Natural) Div(y Natural) Natural {
q, r := divmod(unpack(x), unpack(y)); q, r := divmod(unpack(x), unpack(y));
return pack(q); 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 { func (x Natural) Mod(y Natural) Natural {
q, r := divmod(unpack(x), unpack(y)); q, r := divmod(unpack(x), unpack(y));
return pack(r); 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) { func (x Natural) DivMod(y Natural) (Natural, Natural) {
q, r := divmod(unpack(x), unpack(y)); q, r := divmod(unpack(x), unpack(y));
return pack(q), pack(r); return pack(q), pack(r);
} }
func shl(z, x []Digit, s uint) Digit { func shl(z, x []digit, s uint) digit {
assert(s <= _W); assert(s <= _W);
n := len(x); n := len(x);
c := Digit(0); c := digit(0);
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
c, z[i] = x[i] >> (_W-s), x[i] << s & _M | c; c, z[i] = x[i] >> (_W-s), x[i] << s & _M | c;
} }
...@@ -470,6 +501,8 @@ func shl(z, x []Digit, s uint) Digit { ...@@ -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 { func (x Natural) Shl(s uint) Natural {
n := uint(len(x)); n := uint(len(x));
m := n + s/_W; m := n + s/_W;
...@@ -481,10 +514,10 @@ func (x Natural) Shl(s uint) Natural { ...@@ -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); assert(s <= _W);
n := len(x); n := len(x);
c := Digit(0); c := digit(0);
for i := n - 1; i >= 0; i-- { for i := n - 1; i >= 0; i-- {
c, z[i] = x[i] << (_W-s) & _M, x[i] >> s | c; c, z[i] = x[i] << (_W-s) & _M, x[i] >> s | c;
} }
...@@ -492,6 +525,8 @@ func shr(z, x []Digit, s uint) Digit { ...@@ -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 { func (x Natural) Shr(s uint) Natural {
n := uint(len(x)); n := uint(len(x));
m := n - s/_W; m := n - s/_W;
...@@ -506,6 +541,8 @@ func (x Natural) Shr(s uint) Natural { ...@@ -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 { func (x Natural) And(y Natural) Natural {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -523,13 +560,15 @@ func (x Natural) And(y Natural) Natural { ...@@ -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 { for i, e := range x {
z[i] = e 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 { func (x Natural) Or(y Natural) Natural {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -547,6 +586,8 @@ func (x Natural) Or(y Natural) Natural { ...@@ -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 { func (x Natural) Xor(y Natural) Natural {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -564,6 +605,12 @@ func (x Natural) Xor(y Natural) Natural { ...@@ -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 { func (x Natural) Cmp(y Natural) int {
n := len(x); n := len(x);
m := len(y); m := len(y);
...@@ -585,7 +632,7 @@ func (x Natural) Cmp(y Natural) int { ...@@ -585,7 +632,7 @@ func (x Natural) Cmp(y Natural) int {
} }
func log2(x Digit) uint { func log2(x digit) uint {
assert(x > 0); assert(x > 0);
n := uint(0); n := uint(0);
for x > 0 { for x > 0 {
...@@ -596,6 +643,10 @@ func log2(x Digit) uint { ...@@ -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 { func (x Natural) Log2() uint {
n := len(x); n := len(x);
if n > 0 { if n > 0 {
...@@ -607,10 +658,11 @@ func (x Natural) Log2() uint { ...@@ -607,10 +658,11 @@ func (x Natural) Log2() uint {
// Computes x = x div d in place (modifies x) for "small" d's. // Computes x = x div d in place (modifies x) for "small" d's.
// Returns updated x and x mod d. // 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)); assert(0 < d && isSmall(d - 1));
c := Digit(0); c := digit(0);
for i := len(x) - 1; i >= 0; i-- { for i := len(x) - 1; i >= 0; i-- {
t := c<<_W + x[i]; t := c<<_W + x[i];
c, x[i] = t%d, t/d; c, x[i] = t%d, t/d;
...@@ -620,6 +672,8 @@ func divmod1(x Natural, d Digit) (Natural, Digit) { ...@@ -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 { func (x Natural) ToString(base uint) string {
if len(x) == 0 { if len(x) == 0 {
return "0"; return "0";
...@@ -627,7 +681,7 @@ func (x Natural) ToString(base uint) string { ...@@ -627,7 +681,7 @@ func (x Natural) ToString(base uint) string {
// allocate buffer for conversion // allocate buffer for conversion
assert(2 <= base && base <= 16); 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); s := make([]byte, n);
// don't destroy x // don't destroy x
...@@ -638,8 +692,8 @@ func (x Natural) ToString(base uint) string { ...@@ -638,8 +692,8 @@ func (x Natural) ToString(base uint) string {
i := n; i := n;
for !t.IsZero() { for !t.IsZero() {
i--; i--;
var d Digit; var d digit;
t, d = divmod1(t, Digit(base)); t, d = divmod1(t, digit(base));
s[i] = "0123456789abcdef"[d]; s[i] = "0123456789abcdef"[d];
}; };
...@@ -647,6 +701,9 @@ func (x Natural) ToString(base uint) string { ...@@ -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 { func (x Natural) String() string {
return x.ToString(10); return x.ToString(10);
} }
...@@ -662,6 +719,9 @@ func fmtbase(c int) uint { ...@@ -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) { func (x Natural) Format(h fmt.Formatter, c int) {
fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
} }
...@@ -679,7 +739,8 @@ func hexvalue(ch byte) uint { ...@@ -679,7 +739,8 @@ func hexvalue(ch byte) uint {
// Computes x = x*d + c for "small" d's. // 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)); assert(isSmall(d-1) && isSmall(c));
n := len(x); n := len(x);
z := make(Natural, n + 1); z := make(Natural, n + 1);
...@@ -694,8 +755,17 @@ func muladd1(x Natural, d, c Digit) Natural { ...@@ -694,8 +755,17 @@ func muladd1(x Natural, d, c Digit) Natural {
} }
// Determines base (octal, decimal, hexadecimal) if base == 0. // NatFromString returns the natural number corresponding to the
// Returns the number and base. // 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) { func NatFromString(s string, base uint, slen *int) (Natural, uint) {
// determine base if necessary // determine base if necessary
i, n := 0, len(s); i, n := 0, len(s);
...@@ -716,7 +786,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) { ...@@ -716,7 +786,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) {
for ; i < n; i++ { for ; i < n; i++ {
d := hexvalue(s[i]); d := hexvalue(s[i]);
if d < base { if d < base {
x = muladd1(x, Digit(base), Digit(d)); x = muladd1(x, digit(base), digit(d));
} else { } else {
break; break;
} }
...@@ -733,7 +803,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) { ...@@ -733,7 +803,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) {
// Natural number functions // Natural number functions
func pop1(x Digit) uint { func pop1(x digit) uint {
n := uint(0); n := uint(0);
for x != 0 { for x != 0 {
x &= x-1; x &= x-1;
...@@ -743,6 +813,10 @@ func pop1(x Digit) uint { ...@@ -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 { func (x Natural) Pop() uint {
n := uint(0); n := uint(0);
for i := len(x) - 1; i >= 0; i-- { for i := len(x) - 1; i >= 0; i-- {
...@@ -752,6 +826,8 @@ func (x Natural) Pop() uint { ...@@ -752,6 +826,8 @@ func (x Natural) Pop() uint {
} }
// Pow computes x to the power of n.
//
func (xp Natural) Pow(n uint) Natural { func (xp Natural) Pow(n uint) Natural {
z := Nat(1); z := Nat(1);
x := xp; x := xp;
...@@ -766,6 +842,9 @@ func (xp Natural) Pow(n uint) Natural { ...@@ -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 { func MulRange(a, b uint) Natural {
switch { switch {
case a > b: return Nat(1); case a > b: return Nat(1);
...@@ -778,6 +857,8 @@ func MulRange(a, b uint) Natural { ...@@ -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 { func Fact(n uint) Natural {
// Using MulRange() instead of the basic for-loop // Using MulRange() instead of the basic for-loop
// lead to faster factorial computation. // lead to faster factorial computation.
...@@ -785,18 +866,22 @@ func Fact(n uint) Natural { ...@@ -785,18 +866,22 @@ func Fact(n uint) Natural {
} }
// Binomial computes the binomial coefficient of (n, k).
//
func Binomial(n, k uint) Natural { func Binomial(n, k uint) Natural {
return MulRange(n-k+1, n).Div(MulRange(1, k)); 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. // Euclidean algorithm.
x := xp; a, b := x, y;
for !y.IsZero() { for !b.IsZero() {
x, y = y, x.Mod(y); a, b = b, a.Mod(b);
} }
return x; return a;
} }
...@@ -806,14 +891,18 @@ func (xp Natural) Gcd(y Natural) Natural { ...@@ -806,14 +891,18 @@ func (xp Natural) Gcd(y Natural) Natural {
// Integers are normalized if the mantissa is normalized and the sign is // Integers are normalized if the mantissa is normalized and the sign is
// false for mant == 0. Use MakeInt to create normalized Integers. // false for mant == 0. Use MakeInt to create normalized Integers.
// Integer represents a signed integer value of arbitrary precision.
//
type Integer struct { type Integer struct {
sign bool; sign bool;
mant Natural; 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 { func MakeInt(sign bool, mant Natural) *Integer {
if mant.IsZero() { if mant.IsZero() {
sign = false; // normalize sign = false; // normalize
...@@ -822,6 +911,10 @@ func MakeInt(sign bool, mant Natural) *Integer { ...@@ -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 { func Int(x int) *Integer {
sign := false; sign := false;
var ux uint; var ux uint;
...@@ -843,21 +936,36 @@ func Int(x int) *Integer { ...@@ -843,21 +936,36 @@ func Int(x int) *Integer {
// Predicates // 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 { func (x *Integer) IsOdd() bool {
return x.mant.IsOdd(); return x.mant.IsOdd();
} }
// IsZero returns true iff x == 0.
//
func (x *Integer) IsZero() bool { func (x *Integer) IsZero() bool {
return x.mant.IsZero(); return x.mant.IsZero();
} }
// IsNeg returns true iff x < 0.
//
func (x *Integer) IsNeg() bool { func (x *Integer) IsNeg() bool {
return x.sign && !x.mant.IsZero() return x.sign && !x.mant.IsZero()
} }
// IsPos returns true iff x >= 0.
//
func (x *Integer) IsPos() bool { func (x *Integer) IsPos() bool {
return !x.sign && !x.mant.IsZero() return !x.sign && !x.mant.IsZero()
} }
...@@ -865,11 +973,15 @@ func (x *Integer) IsPos() bool { ...@@ -865,11 +973,15 @@ func (x *Integer) IsPos() bool {
// Operations // Operations
// Neg returns the negated value of x.
//
func (x *Integer) Neg() *Integer { func (x *Integer) Neg() *Integer {
return MakeInt(!x.sign, x.mant); return MakeInt(!x.sign, x.mant);
} }
// Add returns the sum x + y.
//
func (x *Integer) Add(y *Integer) *Integer { func (x *Integer) Add(y *Integer) *Integer {
var z *Integer; var z *Integer;
if x.sign == y.sign { if x.sign == y.sign {
...@@ -892,6 +1004,8 @@ func (x *Integer) Add(y *Integer) *Integer { ...@@ -892,6 +1004,8 @@ func (x *Integer) Add(y *Integer) *Integer {
} }
// Sub returns the difference x - y.
//
func (x *Integer) Sub(y *Integer) *Integer { func (x *Integer) Sub(y *Integer) *Integer {
var z *Integer; var z *Integer;
if x.sign != y.sign { if x.sign != y.sign {
...@@ -914,6 +1028,8 @@ func (x *Integer) Sub(y *Integer) *Integer { ...@@ -914,6 +1028,8 @@ func (x *Integer) Sub(y *Integer) *Integer {
} }
// Mul returns the product x * y.
//
func (x *Integer) Mul(y *Integer) *Integer { func (x *Integer) Mul(y *Integer) *Integer {
// x * y == x * y // x * y == x * y
// x * (-y) == -(x * y) // x * (-y) == -(x * y)
...@@ -923,6 +1039,8 @@ func (x *Integer) Mul(y *Integer) *Integer { ...@@ -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 { func (x *Integer) MulNat(y Natural) *Integer {
// x * y == x * y // x * y == x * y
// (-x) * y == -(x * y) // (-x) * y == -(x * y)
...@@ -930,13 +1048,16 @@ func (x *Integer) MulNat(y Natural) *Integer { ...@@ -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): // Quo and Rem implement T-division and modulus (like C99):
// //
// q = x.Quo(y) = trunc(x/y) (truncation towards zero) // q = x.Quo(y) = trunc(x/y) (truncation towards zero)
// r = x.Rem(y) = x - y*q // 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 { func (x *Integer) Quo(y *Integer) *Integer {
// x / y == x / y // x / y == x / y
// x / (-y) == -(x / y) // x / (-y) == -(x / y)
...@@ -946,6 +1067,11 @@ func (x *Integer) Quo(y *Integer) *Integer { ...@@ -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 { func (x *Integer) Rem(y *Integer) *Integer {
// x % y == x % y // x % y == x % y
// x % (-y) == x % y // x % (-y) == x % y
...@@ -955,23 +1081,28 @@ func (x *Integer) Rem(y *Integer) *Integer { ...@@ -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) { func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) {
q, r := x.mant.DivMod(y.mant); q, r := x.mant.DivMod(y.mant);
return MakeInt(x.sign != y.sign, q), MakeInt(x.sign, r); 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: // Div and Mod implement Euclidian division and modulus:
// //
// d = x.Div(y) // q = x.Div(y)
// m = x.Mod(y) with: 0 <= m < |d| and: y = x*d + m // 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 { func (x *Integer) Div(y *Integer) *Integer {
q, r := x.QuoRem(y); q, r := x.QuoRem(y);
if r.IsNeg() { if r.IsNeg() {
...@@ -985,6 +1116,10 @@ func (x *Integer) Div(y *Integer) *Integer { ...@@ -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 { func (x *Integer) Mod(y *Integer) *Integer {
r := x.Rem(y); r := x.Rem(y);
if r.IsNeg() { if r.IsNeg() {
...@@ -998,6 +1133,8 @@ func (x *Integer) Mod(y *Integer) *Integer { ...@@ -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) { func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) {
q, r := x.QuoRem(y); q, r := x.QuoRem(y);
if r.IsNeg() { if r.IsNeg() {
...@@ -1013,53 +1150,73 @@ func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) { ...@@ -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 { func (x *Integer) Shl(s uint) *Integer {
return MakeInt(x.sign, x.mant.Shl(s)); 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 { func (x *Integer) Shr(s uint) *Integer {
z := MakeInt(x.sign, x.mant.Shr(s)); z := MakeInt(x.sign, x.mant.Shr(s));
if x.IsNeg() { if x.IsNeg() {
panic("UNIMPLEMENTED Integer.Shr() of negative values"); panic("UNIMPLEMENTED Integer.Shr of negative values");
} }
return z; 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 { func (x *Integer) And(y *Integer) *Integer {
var z *Integer; var z *Integer;
if !x.sign && !y.sign { if !x.sign && !y.sign {
z = MakeInt(false, x.mant.And(y.mant)); z = MakeInt(false, x.mant.And(y.mant));
} else { } else {
panic("UNIMPLEMENTED Integer.And() of negative values"); panic("UNIMPLEMENTED Integer.And of negative values");
} }
return z; 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 { func (x *Integer) Or(y *Integer) *Integer {
var z *Integer; var z *Integer;
if !x.sign && !y.sign { if !x.sign && !y.sign {
z = MakeInt(false, x.mant.Or(y.mant)); z = MakeInt(false, x.mant.Or(y.mant));
} else { } else {
panic("UNIMPLEMENTED Integer.Or() of negative values"); panic("UNIMPLEMENTED Integer.Or of negative values");
} }
return z; 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 { func (x *Integer) Xor(y *Integer) *Integer {
var z *Integer; var z *Integer;
if !x.sign && !y.sign { if !x.sign && !y.sign {
z = MakeInt(false, x.mant.Xor(y.mant)); z = MakeInt(false, x.mant.Xor(y.mant));
} else { } else {
panic("UNIMPLEMENTED Integer.Xor() of negative values"); panic("UNIMPLEMENTED Integer.Xor of negative values");
} }
return z; 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 { func (x *Integer) Cmp(y *Integer) int {
// x cmp y == x cmp y // x cmp y == x cmp y
// x cmp (-y) == x // x cmp (-y) == x
...@@ -1079,6 +1236,8 @@ func (x *Integer) Cmp(y *Integer) int { ...@@ -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 { func (x *Integer) ToString(base uint) string {
if x.mant.IsZero() { if x.mant.IsZero() {
return "0"; return "0";
...@@ -1091,18 +1250,33 @@ func (x *Integer) ToString(base uint) string { ...@@ -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 { func (x *Integer) String() string {
return x.ToString(10); 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) { func (x *Integer) Format(h fmt.Formatter, c int) {
fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
} }
// Determines base (octal, decimal, hexadecimal) if base == 0. // IntFromString returns the integer corresponding to the
// Returns the number and base. // 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) { func IntFromString(s string, base uint, slen *int) (*Integer, uint) {
// get sign, if any // get sign, if any
sign := false; sign := false;
...@@ -1126,14 +1300,16 @@ func IntFromString(s string, base uint, slen *int) (*Integer, uint) { ...@@ -1126,14 +1300,16 @@ func IntFromString(s string, base uint, slen *int) (*Integer, uint) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Rational numbers // Rational numbers
// Rational represents a quotient a/b of arbitrary precision.
//
type Rational struct { type Rational struct {
a *Integer; // numerator a *Integer; // numerator
b Natural; // denominator b Natural; // denominator
} }
// Creation // MakeRat makes a rational number given a numerator a and a denominator b.
//
func MakeRat(a *Integer, b Natural) *Rational { func MakeRat(a *Integer, b Natural) *Rational {
f := a.mant.Gcd(b); // f > 0 f := a.mant.Gcd(b); // f > 0
if f.Cmp(Nat(1)) != 0 { if f.Cmp(Nat(1)) != 0 {
...@@ -1144,6 +1320,10 @@ func MakeRat(a *Integer, b Natural) *Rational { ...@@ -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 { func Rat(a0 int, b0 int) *Rational {
a, b := Int(a0), Int(b0); a, b := Int(a0), Int(b0);
if b.sign { if b.sign {
...@@ -1155,21 +1335,30 @@ func Rat(a0 int, b0 int) *Rational { ...@@ -1155,21 +1335,30 @@ func Rat(a0 int, b0 int) *Rational {
// Predicates // Predicates
// IsZero returns true iff x == 0.
//
func (x *Rational) IsZero() bool { func (x *Rational) IsZero() bool {
return x.a.IsZero(); return x.a.IsZero();
} }
// IsNeg returns true iff x < 0.
//
func (x *Rational) IsNeg() bool { func (x *Rational) IsNeg() bool {
return x.a.IsNeg(); return x.a.IsNeg();
} }
// IsPos returns true iff x > 0.
//
func (x *Rational) IsPos() bool { func (x *Rational) IsPos() bool {
return x.a.IsPos(); 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 { func (x *Rational) IsInt() bool {
return x.b.Cmp(Nat(1)) == 0; return x.b.Cmp(Nat(1)) == 0;
} }
...@@ -1177,26 +1366,37 @@ func (x *Rational) IsInt() bool { ...@@ -1177,26 +1366,37 @@ func (x *Rational) IsInt() bool {
// Operations // Operations
// Neg returns the negated value of x.
//
func (x *Rational) Neg() *Rational { func (x *Rational) Neg() *Rational {
return MakeRat(x.a.Neg(), x.b); return MakeRat(x.a.Neg(), x.b);
} }
// Add returns the sum x + y.
//
func (x *Rational) Add(y *Rational) *Rational { 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)); 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 { 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)); 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 { func (x *Rational) Mul(y *Rational) *Rational {
return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b)); 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 { func (x *Rational) Quo(y *Rational) *Rational {
a := x.a.MulNat(y.b); a := x.a.MulNat(y.b);
b := y.a.MulNat(x.b); b := y.a.MulNat(x.b);
...@@ -1207,11 +1407,20 @@ func (x *Rational) Quo(y *Rational) *Rational { ...@@ -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 { func (x *Rational) Cmp(y *Rational) int {
return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b)); 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 { func (x *Rational) ToString(base uint) string {
s := x.a.ToString(base); s := x.a.ToString(base);
if !x.IsInt() { if !x.IsInt() {
...@@ -1221,18 +1430,33 @@ func (x *Rational) ToString(base uint) string { ...@@ -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 { func (x *Rational) String() string {
return x.ToString(10); 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) { func (x *Rational) Format(h fmt.Formatter, c int) {
fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); fmt.Fprintf(h, "%s", x.ToString(fmtbase(c)));
} }
// Determines base (octal, decimal, hexadecimal) if base == 0. // RatFromString returns the rational number corresponding to the
// Returns the number and base of the nominator. // 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) { func RatFromString(s string, base uint, slen *int) (*Rational, uint) {
// read nominator // read nominator
var alen, blen int; var alen, blen int;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment