Commit 88cbe092 authored by Robert Griesemer's avatar Robert Griesemer

math/big: permit passing of an *Int to Float.Int to avoid allocation

Change-Id: I50e83248357928e56c94b88a8764de828f4f5c76
Reviewed-on: https://go-review.googlesource.com/5890Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent 4100f7d9
...@@ -788,13 +788,14 @@ func (x *Float) Float64() (float64, Accuracy) { ...@@ -788,13 +788,14 @@ func (x *Float) Float64() (float64, Accuracy) {
// Int returns the result of truncating x towards zero; or nil // Int returns the result of truncating x towards zero; or nil
// 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) { // If a non-nil *Int argument z is provided, it is used to store
// TODO(gri) accept z argument for result storage (see Float.Rat below) // the result; otherwise a new Int is allocated.
func (x *Float) Int(z *Int) (*Int, Accuracy) {
if debugFloat { if debugFloat {
validate(x) validate(x)
} }
// accuracy for inexact results // accuracy for inexact results
acc = Below // truncation acc := Below // truncation
if x.neg { if x.neg {
acc = Above acc = Above
} }
...@@ -807,7 +808,11 @@ func (x *Float) Int() (res *Int, acc Accuracy) { ...@@ -807,7 +808,11 @@ func (x *Float) Int() (res *Int, acc Accuracy) {
if len(x.mant) == 0 { if len(x.mant) == 0 {
acc = Exact // ±0 acc = Exact // ±0
} }
return new(Int), acc // ±0.xxx // ±0.xxx
if z == nil {
return new(Int), acc
}
return z.SetUint64(0), acc
} }
// x.exp > 0 // x.exp > 0
// x.mant[len(x.mant)-1] != 0 // x.mant[len(x.mant)-1] != 0
...@@ -818,17 +823,20 @@ func (x *Float) Int() (res *Int, acc Accuracy) { ...@@ -818,17 +823,20 @@ func (x *Float) Int() (res *Int, acc Accuracy) {
acc = Exact acc = Exact
} }
// shift mantissa as needed // shift mantissa as needed
res = &Int{neg: x.neg} if z == nil {
z = new(Int)
}
z.neg = x.neg
// TODO(gri) should have a shift that takes positive and negative shift counts // TODO(gri) should have a shift that takes positive and negative shift counts
switch { switch {
case exp > allBits: case exp > allBits:
res.abs = res.abs.shl(x.mant, exp-allBits) z.abs = z.abs.shl(x.mant, exp-allBits)
default: default:
res.abs = res.abs.set(x.mant) z.abs = z.abs.set(x.mant)
case exp < allBits: case exp < allBits:
res.abs = res.abs.shr(x.mant, allBits-exp) z.abs = z.abs.shr(x.mant, allBits-exp)
} }
return return z, acc
} }
// Rat returns x converted into an exact fraction; or nil if x is an infinity. // Rat returns x converted into an exact fraction; or nil if x is an infinity.
......
...@@ -714,7 +714,7 @@ func TestFloatInt(t *testing.T) { ...@@ -714,7 +714,7 @@ func TestFloatInt(t *testing.T) {
{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact}, {"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
} { } {
x := makeFloat(test.x) x := makeFloat(test.x)
res, acc := x.Int() res, acc := x.Int(nil)
got := "nil" got := "nil"
if res != nil { if res != nil {
got = res.String() got = res.String()
...@@ -723,6 +723,15 @@ func TestFloatInt(t *testing.T) { ...@@ -723,6 +723,15 @@ func TestFloatInt(t *testing.T) {
t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc) t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc)
} }
} }
// check that supplied *Int is used
for _, f := range []string{"0", "1", "-1", "1234"} {
x := makeFloat(f)
i := new(Int)
if res, _ := x.Int(i); res != i {
t.Errorf("(%s).Int is not using supplied *Int", f)
}
}
} }
func TestFloatRat(t *testing.T) { func TestFloatRat(t *testing.T) {
...@@ -765,7 +774,7 @@ func TestFloatRat(t *testing.T) { ...@@ -765,7 +774,7 @@ func TestFloatRat(t *testing.T) {
} }
// check that supplied *Rat is used // check that supplied *Rat is used
for _, f := range []string{"0", "1"} { for _, f := range []string{"0", "1", "-1", "1234"} {
x := makeFloat(f) x := makeFloat(f)
r := new(Rat) r := new(Rat)
if res := x.Rat(r); res != r { if res := x.Rat(r); res != r {
......
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