summaryrefslogtreecommitdiff
path: root/src/pkg/bignum/bignum.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/bignum/bignum.go')
-rwxr-xr-xsrc/pkg/bignum/bignum.go139
1 files changed, 103 insertions, 36 deletions
diff --git a/src/pkg/bignum/bignum.go b/src/pkg/bignum/bignum.go
index 665ab9f06..4fe6d0444 100755
--- a/src/pkg/bignum/bignum.go
+++ b/src/pkg/bignum/bignum.go
@@ -59,12 +59,12 @@ type (
const (
- _LogW = 64;
- _LogH = 4; // bits for a hex digit (= small number)
- _LogB = _LogW - _LogH; // largest bit-width available
+ logW = 64;
+ logH = 4; // bits for a hex digit (= small number)
+ logB = logW - logH; // largest bit-width available
// half-digits
- _W2 = _LogB / 2; // width
+ _W2 = logB / 2; // width
_B2 = 1 << _W2; // base
_M2 = _B2 - 1; // mask
@@ -86,11 +86,12 @@ func assert(p bool) {
func isSmall(x digit) bool {
- return x < 1<<_LogH;
+ return x < 1<<logH;
}
-// For debugging.
+// For debugging. Keep around.
+/*
func dump(x []digit) {
print("[", len(x), "]");
for i := len(x) - 1; i >= 0; i-- {
@@ -98,6 +99,7 @@ func dump(x []digit) {
}
println();
}
+*/
// ----------------------------------------------------------------------------
@@ -116,21 +118,66 @@ var (
// 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 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;
}
- assert(digit(x) < _B);
- return Natural{digit(x)};
+
+ // single-digit values
+ if x < _B {
+ return Natural{digit(x)};
+ }
+
+ // compute number of digits required to represent x
+ // (this is usually 1 or 2, but the algorithm works
+ // for any base)
+ n := 0;
+ for t := x; t > 0; t >>= _W {
+ n++;
+ }
+
+ // split x into digits
+ z := make(Natural, n);
+ for i := 0; i < n; i++ {
+ z[i] = digit(x & _M);
+ x >>= _W;
+ }
+
+ return z;
}
+// Value returns the lowest 64bits of x.
+//
+func (x Natural) Value() uint64 {
+ // single-digit values
+ n := len(x);
+ switch n {
+ case 0: return 0;
+ case 1: return uint64(x[0]);
+ }
+
+ // multi-digit values
+ // (this is usually 1 or 2, but the algorithm works
+ // for any base)
+ z := uint64(0);
+ s := uint(0);
+ for i := 0; i < n && s < 64; i++ {
+ z += uint64(x[i]) << s;
+ s += _W;
+ }
+
+ return z;
+}
+
+
+// Predicates
+
// IsEven returns true iff x is divisible by 2.
//
func (x Natural) IsEven() bool {
@@ -632,7 +679,11 @@ func (x Natural) Cmp(y Natural) int {
}
-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 log2(x uint64) uint {
assert(x > 0);
n := uint(0);
for x > 0 {
@@ -650,7 +701,7 @@ func log2(x digit) uint {
func (x Natural) Log2() uint {
n := len(x);
if n > 0 {
- return (uint(n) - 1)*_W + log2(x[n - 1]);
+ return (uint(n) - 1)*_W + log2(uint64(x[n - 1]));
}
panic("Log2(0)");
}
@@ -681,7 +732,7 @@ func (x Natural) ToString(base uint) string {
// allocate buffer for conversion
assert(2 <= base && base <= 16);
- n := (x.Log2() + 1) / log2(digit(base)) + 1; // +1: round up
+ n := (x.Log2() + 1) / log2(uint64(base)) + 1; // +1: round up
s := make([]byte, n);
// don't destroy x
@@ -728,7 +779,7 @@ func (x Natural) Format(h fmt.State, c int) {
func hexvalue(ch byte) uint {
- d := uint(1 << _LogH);
+ d := uint(1 << logH);
switch {
case '0' <= ch && ch <= '9': d = uint(ch - '0');
case 'a' <= ch && ch <= 'f': d = uint(ch - 'a') + 10;
@@ -839,8 +890,8 @@ 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(a);
- case a + 1 == b: return Nat(a).Mul(Nat(b));
+ case a == b: return Nat(uint64(a));
+ case a + 1 == b: return Nat(uint64(a)).Mul(Nat(uint64(b)));
}
m := (a + b)>>1;
assert(a <= m && m < b);
@@ -903,25 +954,36 @@ func MakeInt(sign bool, mant Natural) *Integer {
// Int creates a small integer with value x.
-// Implementation restriction: At the moment, only values
-// with an absolute value |x| < (1<<60) are supported.
//
-func Int(x int) *Integer {
- sign := false;
- var ux uint;
+func Int(x int64) *Integer {
+ var ux uint64;
if x < 0 {
- sign = true;
- if -x == x {
- // smallest negative integer
- t := ^0;
- ux = ^(uint(t) >> 1);
- } else {
- ux = uint(-x);
- }
+ // For the most negative x, -x == x, and
+ // the bit pattern has the correct value.
+ ux = uint64(-x);
} else {
- ux = uint(x);
+ ux = uint64(x);
}
- return MakeInt(sign, Nat(ux));
+ 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;
}
@@ -1303,10 +1365,8 @@ 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 int64, b0 int64) *Rational {
a, b := Int(a0), Int(b0);
if b.sign {
a = a.Neg();
@@ -1315,6 +1375,13 @@ func Rat(a0 int, b0 int) *Rational {
}
+// 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.
@@ -1454,7 +1521,7 @@ func RatFromString(s string, base uint) (*Rational, uint, int) {
alen++;
b, base, blen = NatFromString(s[alen : len(s)], abase);
assert(base == abase);
- f := Nat(base).Pow(uint(blen));
+ f := Nat(uint64(base)).Pow(uint(blen));
a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
b = f;
}