Commit e2fe2f3f authored by Robert Griesemer's avatar Robert Griesemer

- better support for string conversions

- removed trailing tabs

R=r
OCL=18458
CL=18458
parent d289e634
...@@ -180,7 +180,7 @@ func Mul11(x, y Digit) (Digit, Digit) { ...@@ -180,7 +180,7 @@ func Mul11(x, y Digit) (Digit, Digit) {
// z = z1*B + z0 = x*y // z = z1*B + z0 = x*y
z0 := (t1<<W2 + t0)&M; z0 := (t1<<W2 + t0)&M;
z1 := t2<<DW + (t1 + t0>>W2)>>(W-W2); z1 := t2<<DW + (t1 + t0>>W2)>>(W-W2);
return z1, z0; return z1, z0;
} }
...@@ -453,17 +453,17 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { ...@@ -453,17 +453,17 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
assert(n+1 <= cap(x)); // space for one extra digit assert(n+1 <= cap(x)); // space for one extra digit
x = x[0 : n + 1]; x = x[0 : n + 1];
assert(x[n] == 0); assert(x[n] == 0);
if m == 1 { if m == 1 {
// division by single digit // division by single digit
// result is shifted left by 1 in place! // result is shifted left by 1 in place!
x[0] = Div1(x[1 : n+1], x[0 : n], y[0]); x[0] = Div1(x[1 : n+1], x[0 : n], y[0]);
} else if m > n { } else if m > n {
// y > x => quotient = 0, remainder = x // y > x => quotient = 0, remainder = x
// TODO in this case we shouldn't even unpack x and y // TODO in this case we shouldn't even unpack x and y
m = n; m = n;
} else { } else {
// general case // general case
assert(2 <= m && m <= n); assert(2 <= m && m <= n);
...@@ -478,12 +478,12 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { ...@@ -478,12 +478,12 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
Mul1(y, y, Digit2(f)); Mul1(y, y, Digit2(f));
} }
assert(B2/2 <= y[m-1] && y[m-1] < B2); // incorrect scaling assert(B2/2 <= y[m-1] && y[m-1] < B2); // incorrect scaling
y1, y2 := Digit(y[m-1]), Digit(y[m-2]); y1, y2 := Digit(y[m-1]), Digit(y[m-2]);
d2 := Digit(y1)<<W2 + Digit(y2); d2 := Digit(y1)<<W2 + Digit(y2);
for i := n-m; i >= 0; i-- { for i := n-m; i >= 0; i-- {
k := i+m; k := i+m;
// compute trial digit (Knuth) // compute trial digit (Knuth)
var q Digit; var q Digit;
{ x0, x1, x2 := Digit(x[k]), Digit(x[k-1]), Digit(x[k-2]); { x0, x1, x2 := Digit(x[k]), Digit(x[k-1]), Digit(x[k-2]);
...@@ -496,14 +496,14 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { ...@@ -496,14 +496,14 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
q-- q--
} }
} }
// subtract y*q // subtract y*q
c := Digit(0); c := Digit(0);
for j := 0; j < m; j++ { for j := 0; j < m; j++ {
t := c + Digit(x[i+j]) - Digit(y[j])*q; t := c + Digit(x[i+j]) - Digit(y[j])*q;
c, x[i+j] = Digit(int64(t)>>W2), Digit2(t&M2); // requires arithmetic shift! c, x[i+j] = Digit(int64(t)>>W2), Digit2(t&M2); // requires arithmetic shift!
} }
// correct if trial digit was too large // correct if trial digit was too large
if c + Digit(x[k]) != 0 { if c + Digit(x[k]) != 0 {
// add y // add y
...@@ -516,10 +516,10 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) { ...@@ -516,10 +516,10 @@ func DivMod(x, y *[]Digit2) (*[]Digit2, *[]Digit2) {
// correct trial digit // correct trial digit
q--; q--;
} }
x[k] = Digit2(q); x[k] = Digit2(q);
} }
// undo normalization for remainder // undo normalization for remainder
if f != 1 { if f != 1 {
c := Div1(x[0 : m], x[0 : m], Digit2(f)); c := Div1(x[0 : m], x[0 : m], Digit2(f));
...@@ -553,9 +553,9 @@ func (x *Natural) Shl(s uint) *Natural { ...@@ -553,9 +553,9 @@ func (x *Natural) Shl(s uint) *Natural {
n := uint(len(x)); n := uint(len(x));
m := n + s/W; m := n + s/W;
z := new(Natural, m+1); z := new(Natural, m+1);
z[m] = Shl(z[m-n : m], x, s%W); z[m] = Shl(z[m-n : m], x, s%W);
return Normalize(z); return Normalize(z);
} }
...@@ -567,9 +567,9 @@ func (x *Natural) Shr(s uint) *Natural { ...@@ -567,9 +567,9 @@ func (x *Natural) Shr(s uint) *Natural {
m = 0; m = 0;
} }
z := new(Natural, m); z := new(Natural, m);
Shr(z, x[n-m : n], s%W); Shr(z, x[n-m : n], s%W);
return Normalize(z); return Normalize(z);
} }
...@@ -629,7 +629,7 @@ func (x *Natural) Cmp(y *Natural) int { ...@@ -629,7 +629,7 @@ func (x *Natural) Cmp(y *Natural) int {
i := n - 1; i := n - 1;
for i > 0 && x[i] == y[i] { i--; } for i > 0 && x[i] == y[i] { i--; }
d := 0; d := 0;
switch { switch {
case x[i] < y[i]: d = -1; case x[i] < y[i]: d = -1;
...@@ -679,7 +679,7 @@ func (x *Natural) String(base uint) string { ...@@ -679,7 +679,7 @@ func (x *Natural) String(base uint) string {
if len(x) == 0 { if len(x) == 0 {
return "0"; return "0";
} }
// 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(Digit(base)) + 1; // +1: round up
...@@ -688,7 +688,7 @@ func (x *Natural) String(base uint) string { ...@@ -688,7 +688,7 @@ func (x *Natural) String(base uint) string {
// don't destroy x // don't destroy x
t := new(Natural, len(x)); t := new(Natural, len(x));
Or1(t, x, 0); // copy Or1(t, x, 0); // copy
// convert // convert
i := n; i := n;
for !t.IsZero() { for !t.IsZero() {
...@@ -730,7 +730,8 @@ func MulAdd1(x *Natural, d, c Digit) *Natural { ...@@ -730,7 +730,8 @@ func MulAdd1(x *Natural, d, c Digit) *Natural {
// Determines base (octal, decimal, hexadecimal) if base == 0. // Determines base (octal, decimal, hexadecimal) if base == 0.
export func NatFromString(s string, base uint, slen *int) *Natural { // Returns the number and base.
export func NatFromString(s string, base uint, slen *int) (*Natural, uint) {
// determine base if necessary // determine base if necessary
i, n := 0, len(s); i, n := 0, len(s);
if base == 0 { if base == 0 {
...@@ -743,7 +744,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural { ...@@ -743,7 +744,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural {
} }
} }
} }
// convert string // convert string
assert(2 <= base && base <= 16); assert(2 <= base && base <= 16);
x := Nat(0); x := Nat(0);
...@@ -761,7 +762,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural { ...@@ -761,7 +762,7 @@ export func NatFromString(s string, base uint, slen *int) *Natural {
*slen = i; *slen = i;
} }
return x; return x, base;
} }
...@@ -1104,7 +1105,8 @@ func (x *Integer) String(base uint) string { ...@@ -1104,7 +1105,8 @@ func (x *Integer) String(base uint) string {
// Determines base (octal, decimal, hexadecimal) if base == 0. // Determines base (octal, decimal, hexadecimal) if base == 0.
export func IntFromString(s string, base uint, slen *int) *Integer { // Returns the number and base.
export func IntFromString(s string, base uint, slen *int) (*Integer, uint) {
// get sign, if any // get sign, if any
sign := false; sign := false;
if len(s) > 0 && (s[0] == '-' || s[0] == '+') { if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
...@@ -1112,14 +1114,15 @@ export func IntFromString(s string, base uint, slen *int) *Integer { ...@@ -1112,14 +1114,15 @@ export func IntFromString(s string, base uint, slen *int) *Integer {
s = s[1 : len(s)]; s = s[1 : len(s)];
} }
z := MakeInt(sign, NatFromString(s, base, slen)); var mant *Natural;
mant, base = NatFromString(s, base, slen);
// correct slen if necessary // correct slen if necessary
if slen != nil && sign { if slen != nil && sign {
*slen++; *slen++;
} }
return z; return MakeInt(sign, mant), base;
} }
...@@ -1222,24 +1225,33 @@ func (x *Rational) String(base uint) string { ...@@ -1222,24 +1225,33 @@ func (x *Rational) String(base uint) string {
// Determines base (octal, decimal, hexadecimal) if base == 0. // Determines base (octal, decimal, hexadecimal) if base == 0.
export func RatFromString(s string, base uint, slen *int) *Rational { // Returns the number and base of the nominator.
export func RatFromString(s string, base uint, slen *int) (*Rational, uint) {
// read nominator // read nominator
var alen, blen int; var alen, blen int;
a := IntFromString(s, base, &alen); a, abase := IntFromString(s, base, &alen);
b := Nat(1); b := Nat(1);
// read denominator, if any // read denominator or fraction, if any
if alen < len(s) && s[alen] == '/' { if alen < len(s) {
alen++; ch := s[alen];
if alen < len(s) { if ch == '/' {
b = NatFromString(s[alen : len(s)], base, &blen); alen++;
b, base = NatFromString(s[alen : len(s)], base, &blen);
} else if ch == '.' {
alen++;
b, base = NatFromString(s[alen : len(s)], abase, &blen);
assert(base == abase);
f := Nat(base).Pow(uint(blen));
a = MakeInt(a.sign, a.mant.Mul(f).Add(b));
b = f;
} }
} }
// provide number of string bytes consumed if necessary // provide number of string bytes consumed if necessary
if slen != nil { if slen != nil {
*slen = alen + blen; *slen = alen + blen;
} }
return MakeRat(a, b); return MakeRat(a, b), abase;
} }
...@@ -16,22 +16,40 @@ const ( ...@@ -16,22 +16,40 @@ const (
) )
func NatFromString(s string, base uint, slen *int) *Big.Natural {
x, dummy := Big.NatFromString(s, base, slen);
return x;
}
func IntFromString(s string, base uint, slen *int) *Big.Integer {
x, dummy := Big.IntFromString(s, base, slen);
return x;
}
func RatFromString(s string, base uint, slen *int) *Big.Rational {
x, dummy := Big.RatFromString(s, base, slen);
return x;
}
var ( var (
nat_zero = Big.Nat(0); nat_zero = Big.Nat(0);
nat_one = Big.Nat(1); nat_one = Big.Nat(1);
nat_two = Big.Nat(2); nat_two = Big.Nat(2);
a = Big.NatFromString(sa, 10, nil); a = NatFromString(sa, 10, nil);
b = Big.NatFromString(sb, 10, nil); b = NatFromString(sb, 10, nil);
c = Big.NatFromString(sc, 10, nil); c = NatFromString(sc, 10, nil);
p = Big.NatFromString(sp, 10, nil); p = NatFromString(sp, 10, nil);
int_zero = Big.Int(0); int_zero = Big.Int(0);
int_one = Big.Int(1); int_one = Big.Int(1);
int_two = Big.Int(2); int_two = Big.Int(2);
ip = Big.IntFromString(sp, 10, nil); ip = IntFromString(sp, 10, nil);
rat_zero = Big.Rat(0, 1); rat_zero = Big.Rat(0, 1);
rat_half = Big.Rat(1, 2); rat_half = Big.Rat(1, 2);
rat_one = Big.Rat(1, 1); rat_one = Big.Rat(1, 1);
...@@ -89,17 +107,17 @@ func NatConv() { ...@@ -89,17 +107,17 @@ func NatConv() {
test_msg = "NatConvB"; test_msg = "NatConvB";
var slen int; var slen int;
NAT_EQ(0, Big.NatFromString("0", 0, nil), nat_zero); NAT_EQ(0, NatFromString("0", 0, nil), nat_zero);
NAT_EQ(1, Big.NatFromString("123", 0, nil), Big.Nat(123)); NAT_EQ(1, NatFromString("123", 0, nil), Big.Nat(123));
NAT_EQ(2, Big.NatFromString("077", 0, nil), Big.Nat(7*8 + 7)); NAT_EQ(2, NatFromString("077", 0, nil), Big.Nat(7*8 + 7));
NAT_EQ(3, Big.NatFromString("0x1f", 0, nil), Big.Nat(1*16 + 15)); NAT_EQ(3, NatFromString("0x1f", 0, nil), Big.Nat(1*16 + 15));
NAT_EQ(4, Big.NatFromString("0x1fg", 0, &slen), Big.Nat(1*16 + 15)); NAT_EQ(4, NatFromString("0x1fg", 0, &slen), Big.Nat(1*16 + 15));
TEST(4, slen == 4); TEST(4, slen == 4);
test_msg = "NatConvC"; test_msg = "NatConvC";
t := c.Mul(c); t := c.Mul(c);
for base := uint(2); base <= 16; base++ { for base := uint(2); base <= 16; base++ {
NAT_EQ(base, Big.NatFromString(t.String(base), base, nil), t); NAT_EQ(base, NatFromString(t.String(base), base, nil), t);
} }
} }
...@@ -107,16 +125,16 @@ func NatConv() { ...@@ -107,16 +125,16 @@ func NatConv() {
func IntConv() { func IntConv() {
test_msg = "IntConv"; test_msg = "IntConv";
var slen int; var slen int;
INT_EQ(0, Big.IntFromString("0", 0, nil), int_zero); INT_EQ(0, IntFromString("0", 0, nil), int_zero);
INT_EQ(1, Big.IntFromString("-0", 0, nil), int_zero); INT_EQ(1, IntFromString("-0", 0, nil), int_zero);
INT_EQ(2, Big.IntFromString("123", 0, nil), Big.Int(123)); INT_EQ(2, IntFromString("123", 0, nil), Big.Int(123));
INT_EQ(3, Big.IntFromString("-123", 0, nil), Big.Int(-123)); INT_EQ(3, IntFromString("-123", 0, nil), Big.Int(-123));
INT_EQ(4, Big.IntFromString("077", 0, nil), Big.Int(7*8 + 7)); INT_EQ(4, IntFromString("077", 0, nil), Big.Int(7*8 + 7));
INT_EQ(5, Big.IntFromString("-077", 0, nil), Big.Int(-(7*8 + 7))); INT_EQ(5, IntFromString("-077", 0, nil), Big.Int(-(7*8 + 7)));
INT_EQ(6, Big.IntFromString("0x1f", 0, nil), Big.Int(1*16 + 15)); INT_EQ(6, IntFromString("0x1f", 0, nil), Big.Int(1*16 + 15));
INT_EQ(7, Big.IntFromString("-0x1f", 0, nil), Big.Int(-(1*16 + 15))); INT_EQ(7, IntFromString("-0x1f", 0, nil), Big.Int(-(1*16 + 15)));
INT_EQ(8, Big.IntFromString("0x1fg", 0, &slen), Big.Int(1*16 + 15)); INT_EQ(8, IntFromString("0x1fg", 0, &slen), Big.Int(1*16 + 15));
INT_EQ(9, Big.IntFromString("-0x1fg", 0, &slen), Big.Int(-(1*16 + 15))); INT_EQ(9, IntFromString("-0x1fg", 0, &slen), Big.Int(-(1*16 + 15)));
TEST(10, slen == 5); TEST(10, slen == 5);
} }
...@@ -124,12 +142,16 @@ func IntConv() { ...@@ -124,12 +142,16 @@ func IntConv() {
func RatConv() { func RatConv() {
test_msg = "RatConv"; test_msg = "RatConv";
var slen int; var slen int;
RAT_EQ(0, Big.RatFromString("0", 0, nil), rat_zero); RAT_EQ(0, RatFromString("0", 0, nil), rat_zero);
RAT_EQ(1, Big.RatFromString("0/", 0, nil), rat_zero); RAT_EQ(1, RatFromString("0/1", 0, nil), rat_zero);
RAT_EQ(2, Big.RatFromString("0/1", 0, nil), rat_zero); RAT_EQ(2, RatFromString("0/01", 0, nil), rat_zero);
RAT_EQ(3, Big.RatFromString("010/8", 0, nil), rat_one); RAT_EQ(3, RatFromString("0x14/10", 0, &slen), rat_two);
RAT_EQ(4, Big.RatFromString("20/0xa", 0, &slen), rat_two); TEST(4, slen == 7);
TEST(5, slen == 6); RAT_EQ(5, RatFromString("0.", 0, nil), rat_zero);
RAT_EQ(6, RatFromString("0.001f", 10, nil), Big.Rat(1, 1000));
RAT_EQ(7, RatFromString("10101.0101", 2, nil), Big.Rat(0x155, 1<<4));
RAT_EQ(8, RatFromString("-0003.145926", 10, &slen), Big.Rat(-3145926, 1000000));
TEST(9, slen == 12);
} }
...@@ -213,11 +235,11 @@ func NatMul() { ...@@ -213,11 +235,11 @@ func NatMul() {
test_msg = "NatMulA"; test_msg = "NatMulA";
NAT_EQ(0, Mul(c, nat_zero), nat_zero); NAT_EQ(0, Mul(c, nat_zero), nat_zero);
NAT_EQ(1, Mul(c, nat_one), c); NAT_EQ(1, Mul(c, nat_one), c);
test_msg = "NatMulB"; test_msg = "NatMulB";
NAT_EQ(0, b.Mul(Big.MulRange(0, 100)), nat_zero); NAT_EQ(0, b.Mul(Big.MulRange(0, 100)), nat_zero);
NAT_EQ(1, b.Mul(Big.MulRange(21, 100)), c); NAT_EQ(1, b.Mul(Big.MulRange(21, 100)), c);
test_msg = "NatMulC"; test_msg = "NatMulC";
const n = 100; const n = 100;
p := b.Mul(c).Shl(n); p := b.Mul(c).Shl(n);
...@@ -234,7 +256,7 @@ func NatDiv() { ...@@ -234,7 +256,7 @@ func NatDiv() {
NAT_EQ(2, b.Div(c), nat_zero); NAT_EQ(2, b.Div(c), nat_zero);
NAT_EQ(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10)); NAT_EQ(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10));
NAT_EQ(5, c.Div(b), Big.MulRange(21, 100)); NAT_EQ(5, c.Div(b), Big.MulRange(21, 100));
test_msg = "NatDivB"; test_msg = "NatDivB";
const n = 100; const n = 100;
p := Big.Fact(n); p := Big.Fact(n);
...@@ -315,7 +337,7 @@ func NatShift() { ...@@ -315,7 +337,7 @@ func NatShift() {
test_msg = "NatShift1L"; test_msg = "NatShift1L";
TEST(0, b.Shl(0).Cmp(b) == 0); TEST(0, b.Shl(0).Cmp(b) == 0);
TEST(1, c.Shl(1).Cmp(c) > 0); TEST(1, c.Shl(1).Cmp(c) > 0);
test_msg = "NatShift1R"; test_msg = "NatShift1R";
TEST(0, b.Shr(0).Cmp(b) == 0); TEST(0, b.Shr(0).Cmp(b) == 0);
TEST(1, c.Shr(1).Cmp(c) < 0); TEST(1, c.Shr(1).Cmp(c) < 0);
...@@ -349,7 +371,7 @@ func IntShift() { ...@@ -349,7 +371,7 @@ func IntShift() {
test_msg = "IntShift1L"; test_msg = "IntShift1L";
TEST(0, ip.Shl(0).Cmp(ip) == 0); TEST(0, ip.Shl(0).Cmp(ip) == 0);
TEST(1, ip.Shl(1).Cmp(ip) > 0); TEST(1, ip.Shl(1).Cmp(ip) > 0);
test_msg = "IntShift1R"; test_msg = "IntShift1R";
TEST(0, ip.Shr(0).Cmp(ip) == 0); TEST(0, ip.Shr(0).Cmp(ip) == 0);
TEST(1, ip.Shr(1).Cmp(ip) < 0); TEST(1, ip.Shr(1).Cmp(ip) < 0);
...@@ -376,7 +398,7 @@ func IntShift() { ...@@ -376,7 +398,7 @@ func IntShift() {
p = p.Shr(1); p = p.Shr(1);
} }
} }
test_msg = "IntShift4R"; test_msg = "IntShift4R";
//INT_EQ(0, Big.Int(-43).Shr(1), Big.Int(-43 >> 1)); //INT_EQ(0, Big.Int(-43).Shr(1), Big.Int(-43 >> 1));
//INT_EQ(1, ip.Neg().Shr(10), ip.Neg().Div(Big.Int(1).Shl(10))); //INT_EQ(1, ip.Neg().Shr(10), ip.Neg().Div(Big.Int(1).Shl(10)));
...@@ -456,17 +478,17 @@ func main() { ...@@ -456,17 +478,17 @@ func main() {
NatGcd(); NatGcd();
NatPow(); NatPow();
NatPop(); NatPop();
// Integers // Integers
// TODO add more tests // TODO add more tests
IntConv(); IntConv();
IntQuoRem(); IntQuoRem();
IntDivMod(); IntDivMod();
IntShift(); IntShift();
// Rationals // Rationals
// TODO add more tests // TODO add more tests
RatConv(); RatConv();
print("PASSED\n"); print("PASSED\n");
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment