mirror of
https://github.com/golang/go
synced 2024-11-20 06:04:52 -07:00
- removed implementation restrictions for creation of small
Natural, Integer, and Rational numbers - added Value() methods to access small Natural and Integers as uint64 or int64 respectively, and to get the components of Rational numbers - fixed a bug with Integer creation - removed some _'s from names - added more comments in places - added test cases R=rsc DELTA=184 (127 added, 11 deleted, 46 changed) OCL=31210 CL=31265
This commit is contained in:
parent
0417aafe75
commit
8afeb52cac
@ -59,12 +59,12 @@ type (
|
|||||||
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_LogW = 64;
|
logW = 64;
|
||||||
_LogH = 4; // bits for a hex digit (= small number)
|
logH = 4; // bits for a hex digit (= small number)
|
||||||
_LogB = _LogW - _LogH; // largest bit-width available
|
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
|
||||||
_M2 = _B2 - 1; // mask
|
_M2 = _B2 - 1; // mask
|
||||||
|
|
||||||
@ -86,11 +86,12 @@ func assert(p bool) {
|
|||||||
|
|
||||||
|
|
||||||
func isSmall(x digit) bool {
|
func isSmall(x digit) bool {
|
||||||
return x < 1<<_LogH;
|
return x < 1<<logH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For debugging.
|
// For debugging. Keep around.
|
||||||
|
/*
|
||||||
func dump(x []digit) {
|
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-- {
|
||||||
@ -98,6 +99,7 @@ func dump(x []digit) {
|
|||||||
}
|
}
|
||||||
println();
|
println();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -116,20 +118,65 @@ var (
|
|||||||
|
|
||||||
|
|
||||||
// Nat creates a small natural number with value x.
|
// 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 {
|
switch x {
|
||||||
case 0: return natZero;
|
case 0: return natZero;
|
||||||
case 1: return natOne;
|
case 1: return natOne;
|
||||||
case 2: return natTwo;
|
case 2: return natTwo;
|
||||||
case 10: return natTen;
|
case 10: return natTen;
|
||||||
}
|
}
|
||||||
assert(digit(x) < _B);
|
|
||||||
|
// single-digit values
|
||||||
|
if x < _B {
|
||||||
return Natural{digit(x)};
|
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.
|
// IsEven returns true iff x is divisible by 2.
|
||||||
//
|
//
|
||||||
@ -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);
|
assert(x > 0);
|
||||||
n := uint(0);
|
n := uint(0);
|
||||||
for x > 0 {
|
for x > 0 {
|
||||||
@ -650,7 +701,7 @@ func log2(x digit) uint {
|
|||||||
func (x Natural) Log2() uint {
|
func (x Natural) Log2() uint {
|
||||||
n := len(x);
|
n := len(x);
|
||||||
if n > 0 {
|
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)");
|
panic("Log2(0)");
|
||||||
}
|
}
|
||||||
@ -681,7 +732,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(uint64(base)) + 1; // +1: round up
|
||||||
s := make([]byte, n);
|
s := make([]byte, n);
|
||||||
|
|
||||||
// don't destroy x
|
// don't destroy x
|
||||||
@ -728,7 +779,7 @@ func (x Natural) Format(h fmt.State, c int) {
|
|||||||
|
|
||||||
|
|
||||||
func hexvalue(ch byte) uint {
|
func hexvalue(ch byte) uint {
|
||||||
d := uint(1 << _LogH);
|
d := uint(1 << logH);
|
||||||
switch {
|
switch {
|
||||||
case '0' <= ch && ch <= '9': d = uint(ch - '0');
|
case '0' <= ch && ch <= '9': d = uint(ch - '0');
|
||||||
case 'a' <= ch && ch <= 'f': d = uint(ch - 'a') + 10;
|
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 {
|
func MulRange(a, b uint) Natural {
|
||||||
switch {
|
switch {
|
||||||
case a > b: return Nat(1);
|
case a > b: return Nat(1);
|
||||||
case a == b: return Nat(a);
|
case a == b: return Nat(uint64(a));
|
||||||
case a + 1 == b: return Nat(a).Mul(Nat(b));
|
case a + 1 == b: return Nat(uint64(a)).Mul(Nat(uint64(b)));
|
||||||
}
|
}
|
||||||
m := (a + b)>>1;
|
m := (a + b)>>1;
|
||||||
assert(a <= m && m < b);
|
assert(a <= m && m < b);
|
||||||
@ -903,25 +954,36 @@ func MakeInt(sign bool, mant Natural) *Integer {
|
|||||||
|
|
||||||
|
|
||||||
// Int creates a small integer with value x.
|
// 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 int64) *Integer {
|
||||||
sign := false;
|
var ux uint64;
|
||||||
var ux uint;
|
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
sign = true;
|
// For the most negative x, -x == x, and
|
||||||
if -x == x {
|
// the bit pattern has the correct value.
|
||||||
// smallest negative integer
|
ux = uint64(-x);
|
||||||
t := ^0;
|
|
||||||
ux = ^(uint(t) >> 1);
|
|
||||||
} else {
|
} else {
|
||||||
ux = uint(-x);
|
ux = uint64(x);
|
||||||
}
|
}
|
||||||
} else {
|
return MakeInt(x < 0, Nat(ux));
|
||||||
ux = uint(x);
|
|
||||||
}
|
}
|
||||||
return MakeInt(sign, 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.
|
// 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);
|
a, b := Int(a0), Int(b0);
|
||||||
if b.sign {
|
if b.sign {
|
||||||
a = a.Neg();
|
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
|
// Predicates
|
||||||
|
|
||||||
// IsZero returns true iff x == 0.
|
// IsZero returns true iff x == 0.
|
||||||
@ -1454,7 +1521,7 @@ func RatFromString(s string, base uint) (*Rational, uint, int) {
|
|||||||
alen++;
|
alen++;
|
||||||
b, base, blen = NatFromString(s[alen : len(s)], abase);
|
b, base, blen = NatFromString(s[alen : len(s)], abase);
|
||||||
assert(base == 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));
|
a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
|
||||||
b = f;
|
b = f;
|
||||||
}
|
}
|
||||||
|
@ -99,9 +99,31 @@ func rat_eq(n uint, x, y *bignum.Rational) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestNatConv(t *testing.T) {
|
func TestNatConv(t *testing.T) {
|
||||||
tester = t;
|
tester = t;
|
||||||
test_msg = "NatConvA";
|
test_msg = "NatConvA";
|
||||||
|
type entry1 struct { x uint64; s string };
|
||||||
|
tab := []entry1{
|
||||||
|
entry1{0, "0"},
|
||||||
|
entry1{255, "255"},
|
||||||
|
entry1{65535, "65535"},
|
||||||
|
entry1{4294967295, "4294967295"},
|
||||||
|
entry1{18446744073709551615, "18446744073709551615"},
|
||||||
|
};
|
||||||
|
for i, e := range tab {
|
||||||
|
test(100 + uint(i), bignum.Nat(e.x).String() == e.s);
|
||||||
|
test(200 + uint(i), natFromString(e.s, 0, nil).Value() == e.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_msg = "NatConvC";
|
||||||
|
z := uint64(7);
|
||||||
|
for i := uint(0); i <= 64; i++ {
|
||||||
|
test(i, bignum.Nat(z).Value() == z);
|
||||||
|
z <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_msg = "NatConvD";
|
||||||
nat_eq(0, a, bignum.Nat(991));
|
nat_eq(0, a, bignum.Nat(991));
|
||||||
nat_eq(1, b, bignum.Fact(20));
|
nat_eq(1, b, bignum.Fact(20));
|
||||||
nat_eq(2, c, bignum.Fact(100));
|
nat_eq(2, c, bignum.Fact(100));
|
||||||
@ -109,7 +131,7 @@ func TestNatConv(t *testing.T) {
|
|||||||
test(4, b.String() == sb);
|
test(4, b.String() == sb);
|
||||||
test(5, c.String() == sc);
|
test(5, c.String() == sc);
|
||||||
|
|
||||||
test_msg = "NatConvB";
|
test_msg = "NatConvE";
|
||||||
var slen int;
|
var slen int;
|
||||||
nat_eq(10, natFromString("0", 0, nil), nat_zero);
|
nat_eq(10, natFromString("0", 0, nil), nat_zero);
|
||||||
nat_eq(11, natFromString("123", 0, nil), bignum.Nat(123));
|
nat_eq(11, natFromString("123", 0, nil), bignum.Nat(123));
|
||||||
@ -118,22 +140,49 @@ func TestNatConv(t *testing.T) {
|
|||||||
nat_eq(14, natFromString("0x1fg", 0, &slen), bignum.Nat(1*16 + 15));
|
nat_eq(14, natFromString("0x1fg", 0, &slen), bignum.Nat(1*16 + 15));
|
||||||
test(4, slen == 4);
|
test(4, slen == 4);
|
||||||
|
|
||||||
test_msg = "NatConvC";
|
test_msg = "NatConvF";
|
||||||
tmp := c.Mul(c);
|
tmp := c.Mul(c);
|
||||||
for base := uint(2); base <= 16; base++ {
|
for base := uint(2); base <= 16; base++ {
|
||||||
nat_eq(base, natFromString(tmp.ToString(base), base, nil), tmp);
|
nat_eq(base, natFromString(tmp.ToString(base), base, nil), tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
test_msg = "NatConvD";
|
test_msg = "NatConvG";
|
||||||
x := bignum.Nat(100);
|
x := bignum.Nat(100);
|
||||||
y, b, _ := bignum.NatFromString(fmt.Sprintf("%b", &x), 2);
|
y, b, _ := bignum.NatFromString(fmt.Sprintf("%b", &x), 2);
|
||||||
nat_eq(100, y, x);
|
nat_eq(100, y, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func abs(x int64) uint64 {
|
||||||
|
if x < 0 {
|
||||||
|
x = -x;
|
||||||
|
}
|
||||||
|
return uint64(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestIntConv(t *testing.T) {
|
func TestIntConv(t *testing.T) {
|
||||||
tester = t;
|
tester = t;
|
||||||
test_msg = "IntConv";
|
test_msg = "IntConvA";
|
||||||
|
type entry2 struct { x int64; s string };
|
||||||
|
tab := []entry2{
|
||||||
|
entry2{0, "0"},
|
||||||
|
entry2{-128, "-128"},
|
||||||
|
entry2{127, "127"},
|
||||||
|
entry2{-32768, "-32768"},
|
||||||
|
entry2{32767, "32767"},
|
||||||
|
entry2{-2147483648, "-2147483648"},
|
||||||
|
entry2{2147483647, "2147483647"},
|
||||||
|
entry2{-9223372036854775808, "-9223372036854775808"},
|
||||||
|
entry2{9223372036854775807, "9223372036854775807"},
|
||||||
|
};
|
||||||
|
for i, e := range tab {
|
||||||
|
test(100 + uint(i), bignum.Int(e.x).String() == e.s);
|
||||||
|
test(200 + uint(i), intFromString(e.s, 0, nil).Value() == e.x);
|
||||||
|
test(300 + uint(i), bignum.Int(e.x).Abs().Value() == abs(e.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
test_msg = "IntConvB";
|
||||||
var slen int;
|
var slen int;
|
||||||
int_eq(0, intFromString("0", 0, nil), int_zero);
|
int_eq(0, intFromString("0", 0, nil), int_zero);
|
||||||
int_eq(1, intFromString("-0", 0, nil), int_zero);
|
int_eq(1, intFromString("-0", 0, nil), int_zero);
|
||||||
@ -180,7 +229,7 @@ func add(x, y bignum.Natural) bignum.Natural {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func sum(n uint, scale bignum.Natural) bignum.Natural {
|
func sum(n uint64, scale bignum.Natural) bignum.Natural {
|
||||||
s := nat_zero;
|
s := nat_zero;
|
||||||
for ; n > 0; n-- {
|
for ; n > 0; n-- {
|
||||||
s = add(s, bignum.Nat(n).Mul(scale));
|
s = add(s, bignum.Nat(n).Mul(scale));
|
||||||
@ -196,9 +245,9 @@ func TestNatAdd(t *testing.T) {
|
|||||||
nat_eq(1, add(nat_zero, c), c);
|
nat_eq(1, add(nat_zero, c), c);
|
||||||
|
|
||||||
test_msg = "NatAddB";
|
test_msg = "NatAddB";
|
||||||
for i := uint(0); i < 100; i++ {
|
for i := uint64(0); i < 100; i++ {
|
||||||
t := bignum.Nat(i);
|
t := bignum.Nat(i);
|
||||||
nat_eq(i, sum(i, c), t.Mul(t).Add(t).Shr(1).Mul(c));
|
nat_eq(uint(i), sum(i, c), t.Mul(t).Add(t).Shr(1).Mul(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,12 +275,12 @@ func TestNatSub(t *testing.T) {
|
|||||||
nat_eq(1, c.Sub(nat_zero), c);
|
nat_eq(1, c.Sub(nat_zero), c);
|
||||||
|
|
||||||
test_msg = "NatSubB";
|
test_msg = "NatSubB";
|
||||||
for i := uint(0); i < 100; i++ {
|
for i := uint64(0); i < 100; i++ {
|
||||||
t := sum(i, c);
|
t := sum(i, c);
|
||||||
for j := uint(0); j <= i; j++ {
|
for j := uint64(0); j <= i; j++ {
|
||||||
t = t.Sub(mul(bignum.Nat(j), c));
|
t = t.Sub(mul(bignum.Nat(j), c));
|
||||||
}
|
}
|
||||||
nat_eq(i, t, nat_zero);
|
nat_eq(uint(i), t, nat_zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +325,7 @@ func TestNatDiv(t *testing.T) {
|
|||||||
func TestIntQuoRem(t *testing.T) {
|
func TestIntQuoRem(t *testing.T) {
|
||||||
tester = t;
|
tester = t;
|
||||||
test_msg = "IntQuoRem";
|
test_msg = "IntQuoRem";
|
||||||
type T struct { x, y, q, r int };
|
type T struct { x, y, q, r int64 };
|
||||||
a := []T{
|
a := []T{
|
||||||
T{+8, +3, +2, +2},
|
T{+8, +3, +2, +2},
|
||||||
T{+8, -3, -2, +2},
|
T{+8, -3, -2, +2},
|
||||||
@ -303,7 +352,7 @@ func TestIntQuoRem(t *testing.T) {
|
|||||||
func TestIntDivMod(t *testing.T) {
|
func TestIntDivMod(t *testing.T) {
|
||||||
tester = t;
|
tester = t;
|
||||||
test_msg = "IntDivMod";
|
test_msg = "IntDivMod";
|
||||||
type T struct { x, y, q, r int };
|
type T struct { x, y, q, r int64 };
|
||||||
a := []T{
|
a := []T{
|
||||||
T{+8, +3, +2, +2},
|
T{+8, +3, +2, +2},
|
||||||
T{+8, -3, -2, +2},
|
T{+8, -3, -2, +2},
|
||||||
|
Loading…
Reference in New Issue
Block a user