mirror of
https://github.com/golang/go
synced 2024-11-23 17:00:07 -07:00
math/big: implemented Float.Int (truncation of Floats to Ints)
Change-Id: Id98f7333fe6ae1b64e0469c6d01f02360c1f8f55 Reviewed-on: https://go-review.googlesource.com/4481 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
950aa9f1bc
commit
64e7038291
@ -22,7 +22,7 @@ const debugFloat = true // enable for debugging
|
||||
|
||||
// A Float represents a multi-precision floating point number of the form
|
||||
//
|
||||
// sign * mantissa * 2**exponent
|
||||
// sign × mantissa × 2**exponent
|
||||
//
|
||||
// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp (with the
|
||||
// exception of 0 and Inf which have a 0 mantissa and special exponents).
|
||||
@ -231,21 +231,18 @@ func (z *Float) SetMantExp(mant *Float, exp int) *Float {
|
||||
// IsInt reports whether x is an integer.
|
||||
// ±Inf are not considered integers.
|
||||
func (x *Float) IsInt() bool {
|
||||
// pick off easy cases
|
||||
if len(x.mant) == 0 {
|
||||
return x.exp != infExp // x == 0
|
||||
if debugFloat {
|
||||
x.validate()
|
||||
}
|
||||
// x != 0
|
||||
// pick off easy cases
|
||||
if x.exp <= 0 {
|
||||
return false // 0 < |x| <= 0.5
|
||||
// |x| < 1 || |x| == Inf
|
||||
return len(x.mant) == 0 && x.exp != infExp
|
||||
}
|
||||
// x.exp > 0
|
||||
if uint(x.exp) >= x.prec {
|
||||
return true // not enough precision for fractional mantissa
|
||||
}
|
||||
if debugFloat {
|
||||
x.validate()
|
||||
}
|
||||
// x.mant[len(x.mant)-1] != 0
|
||||
// determine minimum required precision for x
|
||||
minPrec := uint(len(x.mant))*_W - x.mant.trailingZeroBits()
|
||||
@ -264,6 +261,9 @@ func (x *Float) IsInf(sign int) bool {
|
||||
// If the exponent's magnitude is too large, z becomes ±Inf.
|
||||
func (z *Float) setExp(e int64) {
|
||||
if -MaxExp <= e && e <= MaxExp {
|
||||
if len(z.mant) == 0 {
|
||||
e = 0
|
||||
}
|
||||
z.exp = int32(e)
|
||||
return
|
||||
}
|
||||
@ -706,9 +706,50 @@ func (x *Float) Float64() (float64, Accuracy) {
|
||||
return math.Float64frombits(s | e<<52 | m), r.acc
|
||||
}
|
||||
|
||||
// BUG(gri) Int is not yet implemented
|
||||
func (x *Float) Int() (*Int, Accuracy) {
|
||||
panic("unimplemented")
|
||||
// Int returns the result of truncating x towards zero; or nil
|
||||
// if x is an infinity. The result is Exact if x.IsInt();
|
||||
// otherwise it is Below for x > 0, and Above for x < 0.
|
||||
func (x *Float) Int() (res *Int, acc Accuracy) {
|
||||
if debugFloat {
|
||||
x.validate()
|
||||
}
|
||||
// accuracy for inexact results
|
||||
acc = Below // truncation
|
||||
if x.neg {
|
||||
acc = Above
|
||||
}
|
||||
// pick off easy cases
|
||||
if x.exp <= 0 {
|
||||
// |x| < 1 || |x| == Inf
|
||||
if x.exp == infExp {
|
||||
return nil, acc // ±Inf
|
||||
}
|
||||
if len(x.mant) == 0 {
|
||||
acc = Exact // ±0
|
||||
}
|
||||
return new(Int), acc // ±0.xxx
|
||||
}
|
||||
// x.exp > 0
|
||||
// x.mant[len(x.mant)-1] != 0
|
||||
// determine minimum required precision for x
|
||||
allBits := uint(len(x.mant)) * _W
|
||||
minPrec := allBits - x.mant.trailingZeroBits()
|
||||
exp := uint(x.exp)
|
||||
if exp >= minPrec {
|
||||
acc = Exact
|
||||
}
|
||||
// shift mantissa as needed
|
||||
res = &Int{neg: x.neg}
|
||||
// TODO(gri) should have a shift that takes positive and negative shift counts
|
||||
switch {
|
||||
case exp > allBits:
|
||||
res.abs = res.abs.shl(x.mant, exp-allBits)
|
||||
default:
|
||||
res.abs = res.abs.set(x.mant)
|
||||
case exp < allBits:
|
||||
res.abs = res.abs.shr(x.mant, allBits-exp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BUG(gri) Rat is not yet implemented
|
||||
@ -1042,7 +1083,6 @@ func (z *Float) Mul(x, y *Float) *Float {
|
||||
}
|
||||
|
||||
// Quo sets z to the rounded quotient x/y and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs. TODO(gri) this should become Inf
|
||||
// Precision, rounding, and accuracy reporting are as for Add.
|
||||
func (z *Float) Quo(x, y *Float) *Float {
|
||||
if z.prec == 0 {
|
||||
|
@ -75,7 +75,7 @@ func makeFloat(s string) *Float {
|
||||
return NewInf(-1)
|
||||
}
|
||||
var x Float
|
||||
x.prec = 100 // TODO(gri) find a better way to do this
|
||||
x.prec = 1000 // TODO(gri) find a better way to do this
|
||||
if _, ok := x.SetString(s); !ok {
|
||||
panic(fmt.Sprintf("%q is not a valid float", s))
|
||||
}
|
||||
@ -553,6 +553,46 @@ func TestFloatSetRat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatInt(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x string
|
||||
out string
|
||||
acc Accuracy
|
||||
}{
|
||||
{"0", "0", Exact},
|
||||
{"+0", "0", Exact},
|
||||
{"-0", "0", Exact},
|
||||
{"Inf", "nil", Below},
|
||||
{"+Inf", "nil", Below},
|
||||
{"-Inf", "nil", Above},
|
||||
{"1", "1", Exact},
|
||||
{"-1", "-1", Exact},
|
||||
{"1.23", "1", Below},
|
||||
{"-1.23", "-1", Above},
|
||||
{"123e-2", "1", Below},
|
||||
{"123e-3", "0", Below},
|
||||
{"123e-4", "0", Below},
|
||||
{"1e-1000", "0", Below},
|
||||
{"-1e-1000", "0", Above},
|
||||
{"1e+10", "10000000000", Exact},
|
||||
{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
|
||||
} {
|
||||
x := makeFloat(test.x)
|
||||
out, acc := x.Int()
|
||||
got := "nil"
|
||||
if out != nil {
|
||||
got = out.String()
|
||||
}
|
||||
if got != test.out || acc != test.acc {
|
||||
t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.out, test.acc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatRat(t *testing.T) {
|
||||
// TODO(gri) implement this
|
||||
}
|
||||
|
||||
// Selected precisions with which to run various tests.
|
||||
var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000}
|
||||
|
||||
@ -678,6 +718,7 @@ func TestFloatAdd64(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFloatMul(t *testing.T) {
|
||||
// TODO(gri) implement this
|
||||
}
|
||||
|
||||
// TestFloatMul64 tests that Float.Mul/Quo of numbers with
|
||||
|
Loading…
Reference in New Issue
Block a user