summaryrefslogtreecommitdiff
path: root/src/pkg/exp/bignum/integer.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exp/bignum/integer.go')
-rw-r--r--src/pkg/exp/bignum/integer.go520
1 files changed, 520 insertions, 0 deletions
diff --git a/src/pkg/exp/bignum/integer.go b/src/pkg/exp/bignum/integer.go
new file mode 100644
index 000000000..a8d26829d
--- /dev/null
+++ b/src/pkg/exp/bignum/integer.go
@@ -0,0 +1,520 @@
+// 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 (
+ "fmt"
+)
+
+// TODO(gri) Complete the set of in-place operations.
+
+// 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) }
+
+
+// Iadd sets z to the sum x + y.
+// z must exist and may be x or y.
+//
+func Iadd(z, x, y *Integer) {
+ if x.sign == y.sign {
+ // x + y == x + y
+ // (-x) + (-y) == -(x + y)
+ z.sign = x.sign
+ Nadd(&z.mant, x.mant, y.mant)
+ } else {
+ // x + (-y) == x - y == -(y - x)
+ // (-x) + y == y - x == -(x - y)
+ if x.mant.Cmp(y.mant) >= 0 {
+ z.sign = x.sign
+ Nsub(&z.mant, x.mant, y.mant)
+ } else {
+ z.sign = !x.sign
+ Nsub(&z.mant, y.mant, x.mant)
+ }
+ }
+}
+
+
+// Add returns the sum x + y.
+//
+func (x *Integer) Add(y *Integer) *Integer {
+ var z Integer
+ Iadd(&z, x, y)
+ return &z
+}
+
+
+func Isub(z, x, y *Integer) {
+ if x.sign != y.sign {
+ // x - (-y) == x + y
+ // (-x) - y == -(x + y)
+ z.sign = x.sign
+ Nadd(&z.mant, x.mant, y.mant)
+ } else {
+ // x - y == x - y == -(y - x)
+ // (-x) - (-y) == y - x == -(x - y)
+ if x.mant.Cmp(y.mant) >= 0 {
+ z.sign = x.sign
+ Nsub(&z.mant, x.mant, y.mant)
+ } else {
+ z.sign = !x.sign
+ Nsub(&z.mant, y.mant, x.mant)
+ }
+ }
+}
+
+
+// Sub returns the difference x - y.
+//
+func (x *Integer) Sub(y *Integer) *Integer {
+ var z Integer
+ Isub(&z, x, y)
+ return &z
+}
+
+
+// Nscale sets *z to the scaled value (*z) * d.
+//
+func Iscale(z *Integer, d int64) {
+ f := uint64(d)
+ if d < 0 {
+ f = uint64(-d)
+ }
+ z.sign = z.sign != (d < 0)
+ Nscale(&z.mant, f)
+}
+
+
+// Mul1 returns the product x * d.
+//
+func (x *Integer) Mul1(d int64) *Integer {
+ f := uint64(d)
+ if d < 0 {
+ f = uint64(-d)
+ }
+ return MakeInt(x.sign != (d < 0), x.mant.Mul1(f))
+}
+
+
+// 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: x = y*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:], base)
+
+ return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen
+}