Commit 4854bd9c authored by Robert Griesemer's avatar Robert Griesemer

big: implemented Rat.Inv

Also:
- changed semantics of return values for [Int|Rat].SetString
  if an error occured (returned value is nil); will expose
  hidden errors where return values are not checked
- added more tests
- various cleanups throughout

Fixes #2384.

R=r
CC=golang-dev
https://golang.org/cl/5312044
parent c6bdef3f
...@@ -58,22 +58,24 @@ func NewInt(x int64) *Int { ...@@ -58,22 +58,24 @@ func NewInt(x int64) *Int {
// Set sets z to x and returns z. // Set sets z to x and returns z.
func (z *Int) Set(x *Int) *Int { func (z *Int) Set(x *Int) *Int {
z.abs = z.abs.set(x.abs) if z != x {
z.neg = x.neg z.abs = z.abs.set(x.abs)
z.neg = x.neg
}
return z return z
} }
// Abs sets z to |x| (the absolute value of x) and returns z. // Abs sets z to |x| (the absolute value of x) and returns z.
func (z *Int) Abs(x *Int) *Int { func (z *Int) Abs(x *Int) *Int {
z.abs = z.abs.set(x.abs) z.Set(x)
z.neg = false z.neg = false
return z return z
} }
// Neg sets z to -x and returns z. // Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int { func (z *Int) Neg(x *Int) *Int {
z.abs = z.abs.set(x.abs) z.Set(x)
z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign z.neg = len(z.abs) > 0 && !z.neg // 0 has no sign
return z return z
} }
...@@ -422,8 +424,8 @@ func (x *Int) Format(s fmt.State, ch int) { ...@@ -422,8 +424,8 @@ func (x *Int) Format(s fmt.State, ch int) {
// scan sets z to the integer value corresponding to the longest possible prefix // scan sets z to the integer value corresponding to the longest possible prefix
// read from r representing a signed integer number in a given conversion base. // read from r representing a signed integer number in a given conversion base.
// It returns z, the actual conversion base used, and an error, if any. In the // It returns z, the actual conversion base used, and an error, if any. In the
// error case, the value of z is undefined. The syntax follows the syntax of // error case, the value of z is undefined but the returned value is nil. The
// integer literals in Go. // syntax follows the syntax of integer literals in Go.
// //
// The base argument must be 0 or a value from 2 through MaxBase. If the base // The base argument must be 0 or a value from 2 through MaxBase. If the base
// is 0, the string prefix determines the actual conversion base. A prefix of // is 0, the string prefix determines the actual conversion base. A prefix of
...@@ -434,7 +436,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) { ...@@ -434,7 +436,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
// determine sign // determine sign
ch, _, err := r.ReadRune() ch, _, err := r.ReadRune()
if err != nil { if err != nil {
return z, 0, err return nil, 0, err
} }
neg := false neg := false
switch ch { switch ch {
...@@ -448,7 +450,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) { ...@@ -448,7 +450,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
// determine mantissa // determine mantissa
z.abs, base, err = z.abs.scan(r, base) z.abs, base, err = z.abs.scan(r, base)
if err != nil { if err != nil {
return z, base, err return nil, base, err
} }
z.neg = len(z.abs) > 0 && neg // 0 has no sign z.neg = len(z.abs) > 0 && neg // 0 has no sign
...@@ -497,7 +499,7 @@ func (x *Int) Int64() int64 { ...@@ -497,7 +499,7 @@ func (x *Int) Int64() int64 {
// SetString sets z to the value of s, interpreted in the given base, // SetString sets z to the value of s, interpreted in the given base,
// and returns z and a boolean indicating success. If SetString fails, // and returns z and a boolean indicating success. If SetString fails,
// the value of z is undefined. // the value of z is undefined but the returned value is nil.
// //
// The base argument must be 0 or a value from 2 through MaxBase. If the base // The base argument must be 0 or a value from 2 through MaxBase. If the base
// is 0, the string prefix determines the actual conversion base. A prefix of // is 0, the string prefix determines the actual conversion base. A prefix of
...@@ -508,10 +510,13 @@ func (z *Int) SetString(s string, base int) (*Int, bool) { ...@@ -508,10 +510,13 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
r := strings.NewReader(s) r := strings.NewReader(s)
_, _, err := z.scan(r, base) _, _, err := z.scan(r, base)
if err != nil { if err != nil {
return z, false return nil, false
} }
_, _, err = r.ReadRune() _, _, err = r.ReadRune()
return z, err == os.EOF // err == os.EOF => scan consumed all of s if err != os.EOF {
return nil, false
}
return z, true // err == os.EOF => scan consumed all of s
} }
// SetBytes interprets buf as the bytes of a big-endian unsigned // SetBytes interprets buf as the bytes of a big-endian unsigned
......
...@@ -311,7 +311,16 @@ func TestSetString(t *testing.T) { ...@@ -311,7 +311,16 @@ func TestSetString(t *testing.T) {
t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
continue continue
} }
if !ok1 || !ok2 { if !ok1 {
if n1 != nil {
t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
}
continue
}
if !ok2 {
if n2 != nil {
t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
}
continue continue
} }
......
...@@ -13,8 +13,8 @@ import ( ...@@ -13,8 +13,8 @@ import (
"strings" "strings"
) )
// A Rat represents a quotient a/b of arbitrary precision. The zero value for // A Rat represents a quotient a/b of arbitrary precision.
// a Rat, 0/0, is not a legal Rat. // The zero value for a Rat, 0/0, is not a legal Rat.
type Rat struct { type Rat struct {
a Int a Int
b nat b nat
...@@ -62,6 +62,39 @@ func (z *Rat) SetInt64(x int64) *Rat { ...@@ -62,6 +62,39 @@ func (z *Rat) SetInt64(x int64) *Rat {
return z return z
} }
// Set sets z to x (by making a copy of x) and returns z.
func (z *Rat) Set(x *Rat) *Rat {
if z != x {
z.a.Set(&x.a)
z.b = z.b.set(x.b)
}
return z
}
// Abs sets z to |x| (the absolute value of x) and returns z.
func (z *Rat) Abs(x *Rat) *Rat {
z.Set(x)
z.a.neg = false
return z
}
// Neg sets z to -x and returns z.
func (z *Rat) Neg(x *Rat) *Rat {
z.Set(x)
z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
return z
}
// Inv sets z to 1/x and returns z.
func (z *Rat) Inv(x *Rat) *Rat {
if len(x.a.abs) == 0 {
panic("division by zero")
}
z.Set(x)
z.a.abs, z.b = z.b, z.a.abs // sign doesn't change
return z
}
// Sign returns: // Sign returns:
// //
// -1 if x < 0 // -1 if x < 0
...@@ -133,17 +166,10 @@ func mulNat(x *Int, y nat) *Int { ...@@ -133,17 +166,10 @@ func mulNat(x *Int, y nat) *Int {
// 0 if x == y // 0 if x == y
// +1 if x > y // +1 if x > y
// //
func (x *Rat) Cmp(y *Rat) (r int) { func (x *Rat) Cmp(y *Rat) int {
return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b)) return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b))
} }
// Abs sets z to |x| (the absolute value of x) and returns z.
func (z *Rat) Abs(x *Rat) *Rat {
z.a.Abs(&x.a)
z.b = z.b.set(x.b)
return z
}
// Add sets z to the sum x+y and returns z. // Add sets z to the sum x+y and returns z.
func (z *Rat) Add(x, y *Rat) *Rat { func (z *Rat) Add(x, y *Rat) *Rat {
a1 := mulNat(&x.a, y.b) a1 := mulNat(&x.a, y.b)
...@@ -183,20 +209,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat { ...@@ -183,20 +209,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
return z.norm() return z.norm()
} }
// Neg sets z to -x (by making a copy of x if necessary) and returns z.
func (z *Rat) Neg(x *Rat) *Rat {
z.a.Neg(&x.a)
z.b = z.b.set(x.b)
return z
}
// Set sets z to x (by making a copy of x if necessary) and returns z.
func (z *Rat) Set(x *Rat) *Rat {
z.a.Set(&x.a)
z.b = z.b.set(x.b)
return z
}
func ratTok(ch int) bool { func ratTok(ch int) bool {
return strings.IndexRune("+-/0123456789.eE", ch) >= 0 return strings.IndexRune("+-/0123456789.eE", ch) >= 0
} }
...@@ -219,23 +231,23 @@ func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error { ...@@ -219,23 +231,23 @@ func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error {
// SetString sets z to the value of s and returns z and a boolean indicating // SetString sets z to the value of s and returns z and a boolean indicating
// success. s can be given as a fraction "a/b" or as a floating-point number // success. s can be given as a fraction "a/b" or as a floating-point number
// optionally followed by an exponent. If the operation failed, the value of z // optionally followed by an exponent. If the operation failed, the value of
// is undefined. // z is undefined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) { func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 { if len(s) == 0 {
return z, false return nil, false
} }
// check for a quotient // check for a quotient
sep := strings.Index(s, "/") sep := strings.Index(s, "/")
if sep >= 0 { if sep >= 0 {
if _, ok := z.a.SetString(s[0:sep], 10); !ok { if _, ok := z.a.SetString(s[0:sep], 10); !ok {
return z, false return nil, false
} }
s = s[sep+1:] s = s[sep+1:]
var err os.Error var err os.Error
if z.b, _, err = z.b.scan(strings.NewReader(s), 10); err != nil { if z.b, _, err = z.b.scan(strings.NewReader(s), 10); err != nil {
return z, false return nil, false
} }
return z.norm(), true return z.norm(), true
} }
...@@ -248,10 +260,10 @@ func (z *Rat) SetString(s string) (*Rat, bool) { ...@@ -248,10 +260,10 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if e >= 0 { if e >= 0 {
if e < sep { if e < sep {
// The E must come after the decimal point. // The E must come after the decimal point.
return z, false return nil, false
} }
if _, ok := exp.SetString(s[e+1:], 10); !ok { if _, ok := exp.SetString(s[e+1:], 10); !ok {
return z, false return nil, false
} }
s = s[0:e] s = s[0:e]
} }
...@@ -261,7 +273,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) { ...@@ -261,7 +273,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
} }
if _, ok := z.a.SetString(s, 10); !ok { if _, ok := z.a.SetString(s, 10); !ok {
return z, false return nil, false
} }
powTen := nat{}.expNN(natTen, exp.abs, nil) powTen := nat{}.expNN(natTen, exp.abs, nil)
if exp.neg { if exp.neg {
......
...@@ -50,8 +50,14 @@ func TestRatSetString(t *testing.T) { ...@@ -50,8 +50,14 @@ func TestRatSetString(t *testing.T) {
for i, test := range setStringTests { for i, test := range setStringTests {
x, ok := new(Rat).SetString(test.in) x, ok := new(Rat).SetString(test.in)
if ok != test.ok || ok && x.RatString() != test.out { if ok {
t.Errorf("#%d got %s want %s", i, x.RatString(), test.out) if !test.ok {
t.Errorf("#%d SetString(%q) expected failure", i, test.in)
} else if x.RatString() != test.out {
t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
}
} else if x != nil {
t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
} }
} }
} }
...@@ -113,8 +119,10 @@ func TestFloatString(t *testing.T) { ...@@ -113,8 +119,10 @@ func TestFloatString(t *testing.T) {
func TestRatSign(t *testing.T) { func TestRatSign(t *testing.T) {
zero := NewRat(0, 1) zero := NewRat(0, 1)
for _, a := range setStringTests { for _, a := range setStringTests {
var x Rat x, ok := new(Rat).SetString(a.in)
x.SetString(a.in) if !ok {
continue
}
s := x.Sign() s := x.Sign()
e := x.Cmp(zero) e := x.Cmp(zero)
if s != e { if s != e {
...@@ -153,12 +161,14 @@ func TestRatCmp(t *testing.T) { ...@@ -153,12 +161,14 @@ func TestRatCmp(t *testing.T) {
func TestIsInt(t *testing.T) { func TestIsInt(t *testing.T) {
one := NewInt(1) one := NewInt(1)
for _, a := range setStringTests { for _, a := range setStringTests {
var x Rat x, ok := new(Rat).SetString(a.in)
x.SetString(a.in) if !ok {
continue
}
i := x.IsInt() i := x.IsInt()
e := x.Denom().Cmp(one) == 0 e := x.Denom().Cmp(one) == 0
if i != e { if i != e {
t.Errorf("got %v; want %v for z = %v", i, e, &x) t.Errorf("got IsInt(%v) == %v; want %v", x, i, e)
} }
} }
} }
...@@ -166,16 +176,50 @@ func TestIsInt(t *testing.T) { ...@@ -166,16 +176,50 @@ func TestIsInt(t *testing.T) {
func TestRatAbs(t *testing.T) { func TestRatAbs(t *testing.T) {
zero := NewRat(0, 1) zero := NewRat(0, 1)
for _, a := range setStringTests { for _, a := range setStringTests {
var z Rat x, ok := new(Rat).SetString(a.in)
z.SetString(a.in) if !ok {
var e Rat continue
e.Set(&z) }
e := new(Rat).Set(x)
if e.Cmp(zero) < 0 { if e.Cmp(zero) < 0 {
e.Sub(zero, &e) e.Sub(zero, e)
}
z := new(Rat).Abs(x)
if z.Cmp(e) != 0 {
t.Errorf("got Abs(%v) = %v; want %v", x, z, e)
}
}
}
func TestRatNeg(t *testing.T) {
zero := NewRat(0, 1)
for _, a := range setStringTests {
x, ok := new(Rat).SetString(a.in)
if !ok {
continue
}
e := new(Rat).Sub(zero, x)
z := new(Rat).Neg(x)
if z.Cmp(e) != 0 {
t.Errorf("got Neg(%v) = %v; want %v", x, z, e)
}
}
}
func TestRatInv(t *testing.T) {
zero := NewRat(0, 1)
for _, a := range setStringTests {
x, ok := new(Rat).SetString(a.in)
if !ok {
continue
}
if x.Cmp(zero) == 0 {
continue // avoid division by zero
} }
z.Abs(&z) e := new(Rat).SetFrac(x.Denom(), x.Num())
if z.Cmp(&e) != 0 { z := new(Rat).Inv(x)
t.Errorf("got z = %v; want %v", &z, &e) if z.Cmp(e) != 0 {
t.Errorf("got Inv(%v) = %v; want %v", x, z, e)
} }
} }
} }
...@@ -186,10 +230,10 @@ type ratBinArg struct { ...@@ -186,10 +230,10 @@ type ratBinArg struct {
} }
func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) { func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
x, _ := NewRat(0, 1).SetString(a.x) x, _ := new(Rat).SetString(a.x)
y, _ := NewRat(0, 1).SetString(a.y) y, _ := new(Rat).SetString(a.y)
z, _ := NewRat(0, 1).SetString(a.z) z, _ := new(Rat).SetString(a.z)
out := f(NewRat(0, 1), x, y) out := f(new(Rat), x, y)
if out.Cmp(z) != 0 { if out.Cmp(z) != 0 {
t.Errorf("%s #%d got %s want %s", name, i, out, z) t.Errorf("%s #%d got %s want %s", name, i, out, z)
......
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