// 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).
// 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()
// 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
}
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
}
// 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 {
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))
}
}
}
+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}
}
func TestFloatMul(t *testing.T) {
+ // TODO(gri) implement this
}
// TestFloatMul64 tests that Float.Mul/Quo of numbers with