mirror of
https://github.com/golang/go
synced 2024-11-23 16:40:03 -07:00
math/big: completed Float.Uint64
Change-Id: Ib3738492a2ec8fc99323e687168b17b7239db6ad Reviewed-on: https://go-review.googlesource.com/4511 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
15fe15a198
commit
764a9cf20d
@ -660,23 +660,66 @@ func high64(x nat) uint64 {
|
||||
return v
|
||||
}
|
||||
|
||||
// TODO(gri) FIX THIS (Inf, rounding mode, errors, accuracy, etc.)
|
||||
func (x *Float) Uint64() uint64 {
|
||||
m := high64(x.mant)
|
||||
s := x.exp
|
||||
if s >= 0 {
|
||||
return m >> (64 - uint(s))
|
||||
// Uint64 returns the unsigned integer resulting from truncating x
|
||||
// towards zero. If 0 <= x < 2**64, the result is Exact if x is an
|
||||
// integer; and Below if x has a fractional part. The result is (0,
|
||||
// Above) for x < 0, and (math.MaxUint64, Below) for x > math.MaxUint64.
|
||||
func (x *Float) Uint64() (uint64, Accuracy) {
|
||||
// TODO(gri) there ought to be an easier way to implement this efficiently
|
||||
if debugFloat {
|
||||
x.validate()
|
||||
}
|
||||
return 0 // imprecise
|
||||
// pick off easy cases
|
||||
if x.exp <= 0 {
|
||||
// |x| < 1 || |x| == Inf
|
||||
if x.exp == infExp {
|
||||
// ±Inf
|
||||
if x.neg {
|
||||
return 0, Above // -Inf
|
||||
}
|
||||
return math.MaxUint64, Below // +Inf
|
||||
}
|
||||
if len(x.mant) == 0 {
|
||||
return 0, Exact // ±0
|
||||
}
|
||||
// 0 < |x| < 1
|
||||
if x.neg {
|
||||
return 0, Above
|
||||
}
|
||||
return 0, Below
|
||||
}
|
||||
// x.exp > 0
|
||||
if x.neg {
|
||||
return 0, Above
|
||||
}
|
||||
// x > 0
|
||||
if x.exp <= 64 {
|
||||
// u = trunc(x) fits into a uint64
|
||||
u := high64(x.mant) >> (64 - uint32(x.exp))
|
||||
// x.mant[len(x.mant)-1] != 0
|
||||
// determine minimum required precision for x
|
||||
minPrec := uint(len(x.mant))*_W - x.mant.trailingZeroBits()
|
||||
if minPrec <= 64 {
|
||||
return u, Exact
|
||||
}
|
||||
return u, Below
|
||||
}
|
||||
// x is too large
|
||||
return math.MaxUint64, Below
|
||||
}
|
||||
|
||||
// TODO(gri) FIX THIS (inf, rounding mode, errors, etc.)
|
||||
func (x *Float) Int64() int64 {
|
||||
v := int64(x.Uint64())
|
||||
if x.neg {
|
||||
return -v
|
||||
m := high64(x.mant)
|
||||
s := x.exp
|
||||
var i int64
|
||||
if s >= 0 {
|
||||
i = int64(m >> (64 - uint(s)))
|
||||
}
|
||||
return v
|
||||
if x.neg {
|
||||
return -i
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Float64 returns the closest float64 value of x
|
||||
|
@ -13,6 +13,14 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (x *Float) uint64() uint64 {
|
||||
u, acc := x.Uint64()
|
||||
if acc != Exact {
|
||||
panic(fmt.Sprintf("%s is not a uint64", x.Format('g', 10)))
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func TestFloatZeroValue(t *testing.T) {
|
||||
// zero (uninitialized) value is a ready-to-use 0.0
|
||||
var x Float
|
||||
@ -52,14 +60,18 @@ func TestFloatZeroValue(t *testing.T) {
|
||||
{1, 2, 0, 0, '*', (*Float).Mul},
|
||||
{2, 0, 1, 0, '*', (*Float).Mul},
|
||||
|
||||
{0, 0, 0, 0, '/', (*Float).Quo},
|
||||
{0, 0, 0, 0, '/', (*Float).Quo}, // = +Inf
|
||||
{0, 2, 1, 2, '/', (*Float).Quo},
|
||||
{1, 2, 0, 0, '/', (*Float).Quo},
|
||||
{1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf
|
||||
{2, 0, 1, 0, '/', (*Float).Quo},
|
||||
} {
|
||||
z := make(test.z)
|
||||
test.op(z, make(test.x), make(test.y))
|
||||
if got := int(z.Int64()); got != test.want {
|
||||
got := 0
|
||||
if !z.IsInf(0) {
|
||||
got = int(z.Int64())
|
||||
}
|
||||
if got != test.want {
|
||||
t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want)
|
||||
}
|
||||
}
|
||||
@ -384,7 +396,7 @@ func TestFloatSetUint64(t *testing.T) {
|
||||
} {
|
||||
var f Float
|
||||
f.SetUint64(want)
|
||||
if got := f.Uint64(); got != want {
|
||||
if got := f.uint64(); got != want {
|
||||
t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
|
||||
}
|
||||
}
|
||||
@ -393,7 +405,7 @@ func TestFloatSetUint64(t *testing.T) {
|
||||
const x uint64 = 0x8765432187654321 // 64 bits needed
|
||||
for prec := uint(1); prec <= 64; prec++ {
|
||||
f := NewFloat(0, prec, ToZero).SetUint64(x)
|
||||
got := f.Uint64()
|
||||
got := f.uint64()
|
||||
want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits
|
||||
if got != want {
|
||||
t.Errorf("got %#x (%s); want %#x", got, f.Format('p', 0), want)
|
||||
@ -553,6 +565,32 @@ func TestFloatSetRat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatUint64(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x string
|
||||
out uint64
|
||||
acc Accuracy
|
||||
}{
|
||||
{"0", 0, Exact},
|
||||
{"-0", 0, Exact},
|
||||
{"-1", 0, Above},
|
||||
{"-Inf", 0, Above},
|
||||
{"-1e-1000", 0, Above},
|
||||
{"1e-1000", 0, Below},
|
||||
{"12345.0", 12345, Exact},
|
||||
{"12345.6", 12345, Below},
|
||||
{"18446744073709551615", 18446744073709551615, Exact},
|
||||
{"18446744073709551615.000000000000000000001", math.MaxUint64, Below},
|
||||
{"1e10000", math.MaxUint64, Below},
|
||||
} {
|
||||
x := makeFloat(test.x)
|
||||
out, acc := x.Uint64()
|
||||
if out != test.out || acc != test.acc {
|
||||
t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatInt(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x string
|
||||
|
Loading…
Reference in New Issue
Block a user