mirror of
https://github.com/golang/go
synced 2024-11-19 04:44:41 -07:00
math/big: implemented Float.Rat
Change-Id: If516e12d4b5dfb6f9288437d270569f7e4e2a1cd Reviewed-on: https://go-review.googlesource.com/5871 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
df5cfe7c1f
commit
3e9e9b4822
@ -789,6 +789,7 @@ func (x *Float) Float64() (float64, Accuracy) {
|
|||||||
// if x is an infinity. The result is Exact if x.IsInt();
|
// if x is an infinity. The result is Exact if x.IsInt();
|
||||||
// otherwise it is Below for x > 0, and Above for x < 0.
|
// otherwise it is Below for x > 0, and Above for x < 0.
|
||||||
func (x *Float) Int() (res *Int, acc Accuracy) {
|
func (x *Float) Int() (res *Int, acc Accuracy) {
|
||||||
|
// TODO(gri) accept z argument for result storage (see Float.Rat below)
|
||||||
if debugFloat {
|
if debugFloat {
|
||||||
validate(x)
|
validate(x)
|
||||||
}
|
}
|
||||||
@ -830,9 +831,45 @@ func (x *Float) Int() (res *Int, acc Accuracy) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// BUG(gri) Rat is not yet implemented
|
// Rat returns x converted into an exact fraction; or nil if x is an infinity.
|
||||||
func (x *Float) Rat() *Rat {
|
// If a non-nil *Rat argument z is provided, it is used to store the result;
|
||||||
panic("unimplemented")
|
// otherwise a new Rat is allocated.
|
||||||
|
func (x *Float) Rat(z *Rat) *Rat {
|
||||||
|
if debugFloat {
|
||||||
|
validate(x)
|
||||||
|
}
|
||||||
|
// pick off easy cases
|
||||||
|
switch x.ord() {
|
||||||
|
case -2, +2:
|
||||||
|
return nil // ±Inf
|
||||||
|
case 0:
|
||||||
|
if z == nil {
|
||||||
|
return new(Rat)
|
||||||
|
}
|
||||||
|
return z.SetInt64(0)
|
||||||
|
}
|
||||||
|
// x != 0 && x != ±Inf
|
||||||
|
allBits := int32(len(x.mant)) * _W
|
||||||
|
// build up numerator and denominator
|
||||||
|
if z == nil {
|
||||||
|
z = new(Rat)
|
||||||
|
}
|
||||||
|
z.a.neg = x.neg
|
||||||
|
switch {
|
||||||
|
case x.exp > allBits:
|
||||||
|
z.a.abs = z.a.abs.shl(x.mant, uint(x.exp-allBits))
|
||||||
|
z.b.abs = z.b.abs[:0] // == 1 (see Rat)
|
||||||
|
return z // already in normal form
|
||||||
|
default:
|
||||||
|
z.a.abs = z.a.abs.set(x.mant)
|
||||||
|
z.b.abs = z.b.abs[:0] // == 1 (see Rat)
|
||||||
|
return z // already in normal form
|
||||||
|
case x.exp < allBits:
|
||||||
|
z.a.abs = z.a.abs.set(x.mant)
|
||||||
|
t := z.b.abs.setUint64(1)
|
||||||
|
z.b.abs = t.shl(t, uint(allBits-x.exp))
|
||||||
|
return z.norm()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
|
// Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
|
||||||
|
@ -149,7 +149,7 @@ func TestFloatMantExp(t *testing.T) {
|
|||||||
frac := makeFloat(test.frac)
|
frac := makeFloat(test.frac)
|
||||||
f, e := x.MantExp(nil)
|
f, e := x.MantExp(nil)
|
||||||
if !feq(f, frac) || e != test.exp {
|
if !feq(f, frac) || e != test.exp {
|
||||||
t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, f.Format('g', 10), e, test.frac, test.exp)
|
t.Errorf("%s.MantExp(nil) = %s, %d; want %s, %d", test.x, f.Format('g', 10), e, test.frac, test.exp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,10 +158,10 @@ func TestFloatMantExpAliasing(t *testing.T) {
|
|||||||
x := makeFloat("0.5p10")
|
x := makeFloat("0.5p10")
|
||||||
z := new(Float)
|
z := new(Float)
|
||||||
if m, _ := x.MantExp(z); m != z {
|
if m, _ := x.MantExp(z); m != z {
|
||||||
t.Fatalf("MantExp didn't use supplied *Float")
|
t.Fatalf("Float.MantExp didn't use supplied *Float")
|
||||||
}
|
}
|
||||||
if _, e := x.MantExp(x); e != 10 {
|
if _, e := x.MantExp(x); e != 10 {
|
||||||
t.Fatalf("MantExp aliasing error: got %d; want 10", e)
|
t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,9 +691,9 @@ func TestFloatInt64(t *testing.T) {
|
|||||||
|
|
||||||
func TestFloatInt(t *testing.T) {
|
func TestFloatInt(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
x string
|
x string
|
||||||
out string
|
want string
|
||||||
acc Accuracy
|
acc Accuracy
|
||||||
}{
|
}{
|
||||||
{"0", "0", Exact},
|
{"0", "0", Exact},
|
||||||
{"+0", "0", Exact},
|
{"+0", "0", Exact},
|
||||||
@ -714,19 +714,64 @@ func TestFloatInt(t *testing.T) {
|
|||||||
{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
|
{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
|
||||||
} {
|
} {
|
||||||
x := makeFloat(test.x)
|
x := makeFloat(test.x)
|
||||||
out, acc := x.Int()
|
res, acc := x.Int()
|
||||||
got := "nil"
|
got := "nil"
|
||||||
if out != nil {
|
if res != nil {
|
||||||
got = out.String()
|
got = res.String()
|
||||||
}
|
}
|
||||||
if got != test.out || acc != test.acc {
|
if got != test.want || acc != test.acc {
|
||||||
t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.out, test.acc)
|
t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFloatRat(t *testing.T) {
|
func TestFloatRat(t *testing.T) {
|
||||||
// TODO(gri) implement this
|
for _, test := range []struct {
|
||||||
|
x, want string
|
||||||
|
}{
|
||||||
|
{"0", "0/1"},
|
||||||
|
{"+0", "0/1"},
|
||||||
|
{"-0", "0/1"},
|
||||||
|
{"Inf", "nil"},
|
||||||
|
{"+Inf", "nil"},
|
||||||
|
{"-Inf", "nil"},
|
||||||
|
{"1", "1/1"},
|
||||||
|
{"-1", "-1/1"},
|
||||||
|
{"1.25", "5/4"},
|
||||||
|
{"-1.25", "-5/4"},
|
||||||
|
{"1e10", "10000000000/1"},
|
||||||
|
{"1p10", "1024/1"},
|
||||||
|
{"-1p-10", "-1/1024"},
|
||||||
|
{"3.14159265", "7244019449799623199/2305843009213693952"},
|
||||||
|
} {
|
||||||
|
x := makeFloat(test.x).SetPrec(64)
|
||||||
|
res := x.Rat(nil)
|
||||||
|
got := "nil"
|
||||||
|
if res != nil {
|
||||||
|
got = res.String()
|
||||||
|
}
|
||||||
|
if got != test.want {
|
||||||
|
t.Errorf("%s: got %s; want %s", test.x, got, test.want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// inverse conversion
|
||||||
|
if res != nil {
|
||||||
|
got := new(Float).SetPrec(64).SetRat(res)
|
||||||
|
if got.Cmp(x) != 0 {
|
||||||
|
t.Errorf("%s: got %s; want %s", test.x, got, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that supplied *Rat is used
|
||||||
|
for _, f := range []string{"0", "1"} {
|
||||||
|
x := makeFloat(f)
|
||||||
|
r := new(Rat)
|
||||||
|
if res := x.Rat(r); res != r {
|
||||||
|
t.Errorf("(%s).Rat is not using supplied *Rat", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFloatAbs(t *testing.T) {
|
func TestFloatAbs(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user