mirror of
https://github.com/golang/go.git
synced 2025-05-29 03:11:26 +00:00
- 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
This commit is contained in:
parent
f0c00f7eee
commit
e62dd7bce9
@ -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\
|
||||
|
||||
phases: a1
|
||||
O3=\
|
||||
rational.$O\
|
||||
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++ {
|
||||
|
500
src/pkg/bignum/integer.go
Normal file
500
src/pkg/bignum/integer.go
Normal file
@ -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;
|
||||
}
|
224
src/pkg/bignum/rational.go
Normal file
224
src/pkg/bignum/rational.go
Normal file
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user