1
0
mirror of https://github.com/golang/go synced 2024-11-26 03:27:58 -07:00

- incorporated feedback per rsc

- fixed a bug and added corresponding test case

R=rsc
DELTA=114  (18 added, 29 deleted, 67 changed)
OCL=28114
CL=28128
This commit is contained in:
Robert Griesemer 2009-04-30 14:43:06 -07:00
parent 83e976d53e
commit 68523603e1
2 changed files with 78 additions and 89 deletions

View File

@ -40,7 +40,7 @@ import "fmt"
// is chosen such that division and multiplication by 10 (for decimal
// string representation) can be done without using extended-precision
// 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
// type (digit) in which these operations are performed. Having this
// buffer also allows for trivial (single-bit) carry computation in
@ -48,7 +48,7 @@ import "fmt"
//
// 2) Long division requires extended-precision (2-digit) division per digit.
// Instead of sacrificing the largest base type for all other operations,
// for division the operands are unpacked into "half-digits", and the
// for division the operands are unpacked into ``half-digits'', and the
// results are packed again. For faster unpacking/packing, the base size
// in bits must be even.
@ -60,7 +60,7 @@ type (
const (
_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
// half-digits
@ -115,7 +115,7 @@ 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.
//
@ -363,15 +363,15 @@ func div1(z, x []digit2, y digit2) digit2 {
// it relies on tripple-precision arithmetic which is why Knuth's method is
// used here.
//
// 1) D. Knuth, "The Art of Computer Programming. Volume 2. Seminumerical
// 1) D. Knuth, The Art of Computer Programming. Volume 2. Seminumerical
// Algorithms." Addison-Wesley, Reading, 1969.
// (Algorithm D, Sec. 4.3.1)
//
// 2) Henry S. Warren, Jr., "A Hacker's Delight". Addison-Wesley, 2003.
// 2) Henry S. Warren, Jr., Hacker's Delight. Addison-Wesley, 2003.
// (9-2 Multiword Division, p.140ff)
//
// 3) P. Brinch Hansen, Multiple-length division revisited: A tour of the
// minefield. "Software - Practice and Experience 24", (June 1994),
// 3) P. Brinch Hansen, ``Multiple-length division revisited: A tour of the
// minefield''. Software - Practice and Experience 24, (June 1994),
// 579-601. John Wiley & Sons, Ltd.
func divmod(x, y []digit2) ([]digit2, []digit2) {
@ -401,7 +401,7 @@ func divmod(x, y []digit2) ([]digit2, []digit2) {
// normalize x and y
// TODO Instead of multiplying, it would be sufficient to
// 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);
if f != 1 {
mul1(x, x, digit2(f));
@ -501,7 +501,7 @@ func shl(z, x []digit, s uint) digit {
}
// Shl implements "shift left" x << s. It returns x * 2^s.
// Shl implements ``shift left'' x << s. It returns x * 2^s.
//
func (x Natural) Shl(s uint) Natural {
n := uint(len(x));
@ -525,7 +525,7 @@ func shr(z, x []digit, s uint) digit {
}
// Shr implements "shift right" x >> s. It returns x / 2^s.
// Shr implements ``shift right'' x >> s. It returns x / 2^s.
//
func (x Natural) Shr(s uint) Natural {
n := uint(len(x));
@ -541,7 +541,7 @@ func (x Natural) Shr(s uint) Natural {
}
// And returns the "bitwise and" x & y for the binary representation of x and y.
// And returns the ``bitwise and'' x & y for the binary representation of x and y.
//
func (x Natural) And(y Natural) Natural {
n := len(x);
@ -567,7 +567,7 @@ func copy(z, x []digit) {
}
// Or returns the "bitwise or" x | y for the binary representation of x and y.
// Or returns the ``bitwise or'' x | y for the binary representation of x and y.
//
func (x Natural) Or(y Natural) Natural {
n := len(x);
@ -586,7 +586,7 @@ func (x Natural) Or(y Natural) Natural {
}
// Xor returns the "bitwise exclusive or" x ^ y for the binary representation of x and y.
// Xor returns the ``bitwise exclusive or'' x ^ y for the binary representation of x and y.
//
func (x Natural) Xor(y Natural) Natural {
n := len(x);
@ -656,7 +656,7 @@ 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.
//
func divmod1(x Natural, d digit) (Natural, digit) {
@ -738,7 +738,7 @@ 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 {
assert(isSmall(d-1) && isSmall(c));
@ -757,16 +757,14 @@ func muladd1(x Natural, d, c digit) Natural {
// NatFromString returns the natural number corresponding to the
// longest possible prefix of s representing a natural number in a
// given conversion base.
// given conversion base, the actual conversion base used, and the
// prefix length.
//
// 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.
// 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) (Natural, uint, int) {
// determine base if necessary
i, n := 0, len(s);
if base == 0 {
@ -792,12 +790,7 @@ func NatFromString(s string, base uint, slen *int) (Natural, uint) {
}
}
// provide number of string bytes consumed if necessary
if slen != nil {
*slen = i;
}
return x, base;
return x, base, i;
}
@ -813,9 +806,7 @@ 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.
// Pop computes the ``population count'' of (the number of 1 bits in) x.
//
func (x Natural) Pop() uint {
n := uint(0);
@ -911,7 +902,7 @@ 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.
//
@ -1056,7 +1047,7 @@ func (x *Integer) MulNat(y Natural) *Integer {
// 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".)
// (Daan Leijen, ``Division and Modulus for Computer Scientists''.)
//
func (x *Integer) Quo(y *Integer) *Integer {
// x / y == x / y
@ -1098,9 +1089,9 @@ func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) {
// 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.
// (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 {
@ -1150,14 +1141,14 @@ func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) {
}
// Shl implements "shift left" x << s. It returns x * 2^s.
// 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));
}
// Shr implements "shift right" x >> s. It returns x / 2^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 {
@ -1169,7 +1160,7 @@ func (x *Integer) Shr(s uint) *Integer {
}
// And returns the "bitwise and" x & y for the binary representation of x and y.
// 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 {
@ -1183,7 +1174,7 @@ func (x *Integer) And(y *Integer) *Integer {
}
// Or returns the "bitwise or" x | y for the binary representation of x and y.
// 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 {
@ -1197,7 +1188,7 @@ func (x *Integer) Or(y *Integer) *Integer {
}
// Xor returns the "bitwise xor" x | y for the binary representation of x and y.
// 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 {
@ -1268,32 +1259,23 @@ func (x *Integer) Format(h fmt.Formatter, c int) {
// IntFromString returns the integer corresponding to the
// longest possible prefix of s representing an integer in a
// given conversion base.
// given conversion base, the actual conversion base used, and
// the prefix length.
//
// 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.
// 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) {
// get sign, if any
sign := false;
func IntFromString(s string, base uint) (*Integer, uint, int) {
// skip sign, if any
i0 := 0;
if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
sign = s[0] == '-';
s = s[1 : len(s)];
i0 = 1;
}
var mant Natural;
mant, base = NatFromString(s, base, slen);
mant, base, slen := NatFromString(s[i0 : len(s)], base);
// correct slen if necessary
if slen != nil && sign {
*slen++;
}
return MakeInt(sign, mant), base;
return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen;
}
@ -1320,7 +1302,7 @@ 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.
//
@ -1419,7 +1401,8 @@ func (x *Rational) Cmp(y *Rational) int {
// ToString converts x to a string for a given base, with 2 <= base <= 16.
// The string representation is of the form "numerator/denominator".
// 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);
@ -1448,30 +1431,28 @@ func (x *Rational) Format(h fmt.Formatter, c int) {
// RatFromString returns the rational number corresponding to the
// longest possible prefix of s representing a rational number in a
// given conversion base.
// given conversion base, the actual conversion base used, and the
// prefix length.
//
// 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.
// 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) (*Rational, uint, int) {
// read nominator
var alen, blen int;
a, abase := IntFromString(s, base, &alen);
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 = NatFromString(s[alen : len(s)], base, &blen);
b, base, blen = NatFromString(s[alen : len(s)], base);
} else if ch == '.' {
alen++;
b, base = NatFromString(s[alen : len(s)], abase, &blen);
b, base, blen = NatFromString(s[alen : len(s)], abase);
assert(base == abase);
f := Nat(base).Pow(uint(blen));
a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
@ -1479,10 +1460,5 @@ func RatFromString(s string, base uint, slen *int) (*Rational, uint) {
}
}
// provide number of string bytes consumed if necessary
if slen != nil {
*slen = alen + blen;
}
return MakeRat(a, b), abase;
return MakeRat(a, b), base, alen + blen;
}

View File

@ -20,19 +20,28 @@ const (
)
func natFromString(s string, base uint, slen *int) bignum.Natural {
x, dummy := bignum.NatFromString(s, base, slen);
x, _, len := bignum.NatFromString(s, base);
if slen != nil {
*slen = len;
}
return x;
}
func intFromString(s string, base uint, slen *int) *bignum.Integer {
x, dummy := bignum.IntFromString(s, base, slen);
x, _, len := bignum.IntFromString(s, base);
if slen != nil {
*slen = len;
}
return x;
}
func ratFromString(s string, base uint, slen *int) *bignum.Rational {
x, dummy := bignum.RatFromString(s, base, slen);
x, _, len := bignum.RatFromString(s, base);
if slen != nil {
*slen = len;
}
return x;
}
@ -79,14 +88,14 @@ func nat_eq(n uint, x, y bignum.Natural) {
func int_eq(n uint, x, y *bignum.Integer) {
if x.Cmp(y) != 0 {
tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, &x, &y);
tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y);
}
}
func rat_eq(n uint, x, y *bignum.Rational) {
if x.Cmp(y) != 0 {
tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, &x, &y);
tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y);
}
}
@ -117,7 +126,7 @@ func TestNatConv(t *testing.T) {
test_msg = "NatConvD";
x := bignum.Nat(100);
y, b := bignum.NatFromString(fmt.Sprintf("%b", &x), 2, nil);
y, b, _ := bignum.NatFromString(fmt.Sprintf("%b", &x), 2);
nat_eq(100, y, x);
}
@ -133,9 +142,13 @@ func TestIntConv(t *testing.T) {
int_eq(4, intFromString("077", 0, nil), bignum.Int(7*8 + 7));
int_eq(5, intFromString("-077", 0, nil), bignum.Int(-(7*8 + 7)));
int_eq(6, intFromString("0x1f", 0, nil), bignum.Int(1*16 + 15));
int_eq(7, intFromString("-0x1f", 0, nil), bignum.Int(-(1*16 + 15)));
int_eq(8, intFromString("0x1fg", 0, &slen), bignum.Int(1*16 + 15));
int_eq(9, intFromString("-0x1fg", 0, &slen), bignum.Int(-(1*16 + 15)));
int_eq(7, intFromString("-0x1f", 0, &slen), bignum.Int(-(1*16 + 15)));
test(7, slen == 5);
int_eq(8, intFromString("+0x1f", 0, &slen), bignum.Int(+(1*16 + 15)));
test(8, slen == 5);
int_eq(9, intFromString("0x1fg", 0, &slen), bignum.Int(1*16 + 15));
test(9, slen == 4);
int_eq(10, intFromString("-0x1fg", 0, &slen), bignum.Int(-(1*16 + 15)));
test(10, slen == 5);
}