//
// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp.
// A Float may also be zero (+0, -0), infinite (+Inf, -Inf) or
-// not-a-number (NaN).
+// not-a-number (NaN). Except for NaNs, all Floats are ordered,
+// and the ordering of two Floats x and y is defined by x.Cmp(y).
+// NaNs are always different from any other Float value.
//
// Each Float value also has a precision, rounding mode, and accuracy.
// The precision is the maximum number of mantissa bits available to
prec uint32
mode RoundingMode
acc Accuracy
+ form form
neg bool
mant nat
exp int32
}
-// Internal representation: The mantissa bits x.mant of a Float x are stored
-// in a nat slice long enough to hold up to x.prec bits; the slice may (but
-// doesn't have to) be shorter if the mantissa contains trailing 0 bits.
-// Unless x is a zero, infinity, or NaN, x.mant is normalized such that the
-// msb of x.mant == 1 (i.e., the msb is shifted all the way "to the left").
-// Thus, if the mantissa has trailing 0 bits or x.prec is not a multiple
-// of the the Word size _W, x.mant[0] has trailing zero bits. Zero, Inf, and
-// NaN values have an empty mantissa and a 0, infExp, or NanExp exponent,
-// respectively.
+// Exponent and precision limits.
+const (
+ MaxExp = math.MaxInt32 // largest supported exponent
+ MinExp = math.MinInt32 // smallest supported exponent
+ MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
+)
+
+// Internal representation: The mantissa bits x.mant of a nonzero finite
+// Float x are stored in a nat slice long enough to hold up to x.prec bits;
+// the slice may (but doesn't have to) be shorter if the mantissa contains
+// trailing 0 bits. x.mant is normalized if the msb of x.mant == 1 (i.e.,
+// the msb is shifted all the way "to the left"). Thus, if the mantissa has
+// trailing 0 bits or x.prec is not a multiple of the the Word size _W,
+// x.mant[0] has trailing zero bits. The msb of the mantissa corresponds
+// to the value 0.5; the exponent x.exp shifts the binary point as needed.
+//
+// A zero or non-finite Float x ignores x.mant and x.exp. A NaN x ignores
+// the sign x.neg.
+//
+// x form neg mant exp
+// ----------------------------------------------------------
+// ±0 zero sign - -
+// 0 < |x| < +Inf finite sign mantissa exponent
+// ±Inf inf sign - -
+// NaN nan - - -
+// A form value describes the internal representation.
+type form byte
+
+// The form value order is relevant - do not change!
const (
- MaxExp = math.MaxInt32 // largest supported exponent
- MinExp = math.MinInt32 + 2 // smallest supported exponent
- infExp = math.MinInt32 + 1 // exponent for Inf values
- nanExp = math.MinInt32 + 0 // exponent for NaN values
- MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
+ zero form = iota
+ finite
+ inf
+ nan
)
// RoundingMode determines how a Float value is rounded to the
//go:generate stringer -type=Accuracy
+func (x *Float) cmpZero() Accuracy {
+ if x.neg {
+ return Above
+ }
+ return Below
+}
+
// SetPrec sets z's precision to prec and returns the (possibly) rounded
// value of z. Rounding occurs according to z's rounding mode if the mantissa
// cannot be represented in prec bits without loss of precision.
// special case
if prec == 0 {
z.prec = 0
- if len(z.mant) != 0 {
- // truncate and compute accuracy
- z.setZero()
- acc := Below
- if z.neg {
- acc = Above
- }
- z.acc = acc
+ if z.form == finite {
+ // truncate z to 0
+ z.acc = z.cmpZero()
+ z.form = zero
}
return z
}
// MinPrec returns the minimum precision required to represent x exactly
// (i.e., the smallest prec before x.SetPrec(prec) would start rounding x).
-// The result is 0 for ±0, ±Inf, and NaN.
+// The result is 0 if x is 0 or not finite.
func (x *Float) MinPrec() uint {
+ if x.form != finite {
+ return 0
+ }
return uint(len(x.mant))*_W - x.mant.trailingZeroBits()
}
if debugFloat {
x.validate()
}
- if len(x.mant) == 0 && x.exp != infExp {
+ if x.form == zero || x.form == nan {
return 0
}
if x.neg {
if debugFloat {
x.validate()
}
- if len(x.mant) != 0 {
+ if x.form == finite {
exp = int(x.exp)
}
if mant != nil {
mant.Copy(x)
- if x.exp >= MinExp {
+ if mant.form == finite {
mant.exp = 0
}
}
return
}
+// setExp sets the exponent for z.
+// If e < MinExp, z becomes ±0; if e > MaxExp, z becomes ±Inf.
+func (z *Float) setExp(e int64) {
+ if debugFloat && z.form != finite {
+ panic("setExp called for non-finite Float")
+ }
+ switch {
+ case e < MinExp:
+ // TODO(gri) check that accuracy is adjusted if necessary
+ z.form = zero // underflow
+ default:
+ z.exp = int32(e)
+ case e > MaxExp:
+ // TODO(gri) check that accuracy is adjusted if necessary
+ z.form = inf // overflow
+ }
+}
+
// SetMantExp sets z to mant × 2**exp and and returns z.
// The result z has the same precision and rounding mode
// as mant. SetMantExp is an inverse of MantExp but does
mant.validate()
}
z.Copy(mant)
- if len(z.mant) == 0 {
+ if z.form != finite {
return z
}
z.setExp(int64(z.exp) + int64(exp))
// IsNeg reports whether x is negative.
// A NaN value is not negative.
func (x *Float) IsNeg() bool {
- return x.neg && x.exp != nanExp
+ return x.neg && x.form != nan
}
// IsZero reports whether x is +0 or -0.
func (x *Float) IsZero() bool {
- return len(x.mant) == 0 && x.exp == 0
+ return x.form == zero
}
// IsFinite reports whether -Inf < x < Inf.
// A NaN value is not finite.
func (x *Float) IsFinite() bool {
- return len(x.mant) != 0 || x.exp == 0
+ return x.form <= finite
}
// IsInf reports whether x is +Inf or -Inf.
func (x *Float) IsInf() bool {
- return x.exp == infExp
+ return x.form == inf
}
// IsNaN reports whether x is a NaN value.
func (x *Float) IsNaN() bool {
- return x.exp == nanExp
+ return x.form == nan
}
// IsInt reports whether x is an integer.
if debugFloat {
x.validate()
}
- // pick off easy cases
+ // special cases
+ if x.form != finite {
+ return x.form == zero
+ }
+ // x.form == finite
if x.exp <= 0 {
- // |x| < 1 || |x| == Inf || x is NaN
- return len(x.mant) == 0 && x.exp == 0 // x == 0
+ return false
}
// x.exp > 0
return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa
}
-func (z *Float) setZero() {
- z.mant = z.mant[:0]
- z.exp = 0
-}
-
-func (z *Float) setInf() {
- z.mant = z.mant[:0]
- z.exp = infExp
-}
-
-// setExp sets the exponent for z.
-// If e < MinExp, z becomes ±0; if e > MaxExp, z becomes ±Inf.
-func (z *Float) setExp(e int64) {
- switch {
- case e < MinExp:
- z.setZero()
- default:
- if len(z.mant) == 0 {
- e = 0
- }
- z.exp = int32(e)
- case e > MaxExp:
- z.setInf()
- }
-}
-
// debugging support
func (x *Float) validate() {
if !debugFloat {
// avoid performance bugs
panic("validate called but debugFloat is not set")
}
- const msb = 1 << (_W - 1)
+ if x.form != finite {
+ return
+ }
m := len(x.mant)
if m == 0 {
- // 0.0, Inf, or NaN
- if x.exp != 0 && x.exp >= MinExp {
- panic(fmt.Sprintf("empty matissa with invalid exponent %d", x.exp))
- }
- return
+ panic("nonzero finite x with empty mantissa")
}
+ const msb = 1 << (_W - 1)
if x.mant[m-1]&msb == 0 {
panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
}
func (z *Float) round(sbit uint) {
if debugFloat {
z.validate()
+ if z.form > finite {
+ panic(fmt.Sprintf("round called for non-finite value %s", z))
+ }
}
+ // z.form <= finite
z.acc = Exact
-
- // handle zero, Inf, and NaN
- m := uint32(len(z.mant)) // present mantissa length in words
- if m == 0 {
- if z.exp == nanExp {
- z.acc = Undef
- }
+ if z.form == zero {
return
}
+ // z.form == finite && len(z.mant) > 0
// m > 0 implies z.prec > 0 (checked by validate)
- bits := m * _W // present mantissa bits
+ m := uint32(len(z.mant)) // present mantissa length in words
+ bits := m * _W // present mantissa bits
if bits <= z.prec {
// mantissa fits => nothing to do
return
// zero out trailing bits in least-significant word
z.mant[0] &^= lsb - 1
+ // TODO(gri) can z.mant be all 0s at this point?
+
// update accuracy
if z.acc != Exact && z.neg {
z.acc ^= Below | Above
z.acc = Exact
z.neg = neg
if x == 0 {
- z.setZero()
+ z.form = zero
return z
}
// x != 0
+ z.form = finite
s := nlz64(x)
z.mant = z.mant.setUint64(x << s)
z.exp = int32(64 - s) // always fits
z.prec = 53
}
if math.IsNaN(x) {
- z.SetNaN()
- return z
+ return z.SetNaN()
}
z.acc = Exact
z.neg = math.Signbit(x) // handle -0, -Inf correctly
- if math.IsInf(x, 0) {
- z.setInf()
+ if x == 0 {
+ z.form = zero
return z
}
- if x == 0 {
- z.setZero()
+ if math.IsInf(x, 0) {
+ z.form = inf
return z
}
// normalized x != 0
+ z.form = finite
fmant, exp := math.Frexp(x) // get normalized mantissa
z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
z.exp = int32(exp) // always fits
z.acc = Exact
z.neg = x.neg
if len(x.abs) == 0 {
- z.mant = z.mant[:0]
- z.exp = 0
+ z.form = zero
return z
}
// x != 0
+ z.form = finite
z.mant = z.mant.set(x.abs)
fnorm(z.mant)
z.setExp(int64(bits))
// z is unchanged and the result is always Exact.
func (z *Float) SetInf(sign int) *Float {
z.acc = Exact
+ z.form = inf
z.neg = sign < 0
- z.setInf()
return z
}
// SetNaN sets z to a NaN value, and returns z.
-// The precision of z is unchanged and the result is always Exact.
+// The precision of z is unchanged and the result is always Undef.
func (z *Float) SetNaN() *Float {
- z.acc = Exact
- z.neg = false
- z.mant = z.mant[:0]
- z.exp = nanExp
+ z.acc = Undef
+ z.form = nan
return z
}
if z.prec == 0 {
z.prec = x.prec
}
+ z.form = x.form
z.neg = x.neg
z.exp = x.exp
z.mant = z.mant.set(x.mant)
z.prec = x.prec
z.mode = x.mode
z.acc = x.acc
+ z.form = x.form
z.neg = x.neg
z.mant = z.mant.set(x.mant)
z.exp = x.exp
x.validate()
}
- // special cases
- if len(x.mant) == 0 {
- switch x.exp {
- case 0:
- return 0, Exact // ±0
- case infExp:
- if x.neg {
- return 0, Above // -Inf
+ switch x.form {
+ case finite:
+ if x.neg {
+ return 0, Above
+ }
+ // 0 < x < +Inf
+ if x.exp <= 0 {
+ // 0 < x < 1
+ return 0, Below
+ }
+ // 1 <= x < Inf
+ if x.exp <= 64 {
+ // u = trunc(x) fits into a uint64
+ u := high64(x.mant) >> (64 - uint32(x.exp))
+ if x.MinPrec() <= 64 {
+ return u, Exact
}
- return math.MaxUint64, Below // +Inf
- case nanExp:
- return 0, Undef // NaN
+ return u, Below // x truncated
}
- panic("unreachable")
- }
+ // x too large
+ return math.MaxUint64, Below
- if x.neg {
- return 0, Above
- }
- // x > 0
- if x.exp <= 0 {
- // 0 < x < 1
- return 0, Below
- }
- // 1 <= x
- if x.exp <= 64 {
- // u = trunc(x) fits into a uint64
- u := high64(x.mant) >> (64 - uint32(x.exp))
- if x.MinPrec() <= 64 {
- return u, Exact
+ case zero:
+ return 0, Exact
+
+ case inf:
+ if x.neg {
+ return 0, Above
}
- return u, Below // x truncated
+ return math.MaxUint64, Below
+
+ case nan:
+ return 0, Undef
}
- // x too large
- return math.MaxUint64, Below
+
+ panic("unreachable")
}
// Int64 returns the integer resulting from truncating x towards zero.
x.validate()
}
- // special cases
- if len(x.mant) == 0 {
- switch x.exp {
- case 0:
- return 0, Exact // ±0
- case infExp:
+ switch x.form {
+ case finite:
+ // 0 < |x| < +Inf
+ acc := x.cmpZero()
+ if x.exp <= 0 {
+ // 0 < |x| < 1
+ return 0, acc
+ }
+ // x.exp > 0
+
+ // 1 <= |x| < +Inf
+ if x.exp <= 63 {
+ // i = trunc(x) fits into an int64 (excluding math.MinInt64)
+ i := int64(high64(x.mant) >> (64 - uint32(x.exp)))
if x.neg {
- return math.MinInt64, Above // -Inf
+ i = -i
}
- return math.MaxInt64, Below // +Inf
- case nanExp:
- return 0, Undef // NaN
+ if x.MinPrec() <= 63 {
+ return i, Exact
+ }
+ return i, acc // x truncated
}
- panic("unreachable")
- }
+ if x.neg {
+ // check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
+ if x.exp == 64 && x.MinPrec() == 1 {
+ acc = Exact
+ }
+ return math.MinInt64, acc
+ }
+ // x too large
+ return math.MaxInt64, Below
- // 0 < |x| < +Inf
- acc := Below
- if x.neg {
- acc = Above
- }
- if x.exp <= 0 {
- // 0 < |x| < 1
- return 0, acc
- }
- // x.exp > 0
+ case zero:
+ return 0, Exact
- // 1 <= |x| < +Inf
- if x.exp <= 63 {
- // i = trunc(x) fits into an int64 (excluding math.MinInt64)
- i := int64(high64(x.mant) >> (64 - uint32(x.exp)))
+ case inf:
if x.neg {
- i = -i
- }
- if x.MinPrec() <= 63 {
- return i, Exact
+ return math.MinInt64, Above
}
- return i, acc // x truncated
- }
- if x.neg {
- // check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
- if x.exp == 64 && x.MinPrec() == 1 {
- acc = Exact
- }
- return math.MinInt64, acc
+ return math.MaxInt64, Below
+
+ case nan:
+ return 0, Undef
}
- // x == +Inf
- return math.MaxInt64, Below
+
+ panic("unreachable")
}
// Float64 returns the closest float64 value of x
x.validate()
}
- // special cases
- if len(x.mant) == 0 {
- switch x.exp {
- case 0:
- if x.neg {
- var zero float64
- return -zero, Exact
- }
- return 0, Exact
- case infExp:
- var sign int
- if x.neg {
- sign = -1
- }
- return math.Inf(sign), Exact
- case nanExp:
- return math.NaN(), Undef
+ switch x.form {
+ case finite:
+ // 0 < |x| < +Inf
+ var r Float
+ r.prec = 53
+ r.Set(x)
+ var s uint64
+ if r.neg {
+ s = 1 << 63
}
- panic("unreachable")
- }
+ e := uint64(1022+r.exp) & 0x7ff // TODO(gri) check for overflow
+ m := high64(r.mant) >> 11 & (1<<52 - 1)
+ return math.Float64frombits(s | e<<52 | m), r.acc
+
+ case zero:
+ z := 0.0
+ if x.neg {
+ z = -z
+ }
+ return z, Exact
+
+ case inf:
+ sign := +1
+ if x.neg {
+ sign = -1
+ }
+ return math.Inf(sign), Exact
- // 0 < |x| < +Inf
- var r Float
- r.prec = 53
- r.Set(x)
- var s uint64
- if r.neg {
- s = 1 << 63
+ case nan:
+ return math.NaN(), Undef
}
- e := uint64(1022+r.exp) & 0x7ff // TODO(gri) check for overflow
- m := high64(r.mant) >> 11 & (1<<52 - 1)
- return math.Float64frombits(s | e<<52 | m), r.acc
+
+ panic("unreachable")
}
// Int returns the result of truncating x towards zero;
x.validate()
}
- if z == nil {
- // no need to do this for Inf and NaN
- // but those are rare enough that we
- // don't care
+ if z == nil && x.form <= finite {
z = new(Int)
}
- // special cases
- if len(x.mant) == 0 {
- switch x.exp {
- case 0:
- return z.SetInt64(0), Exact // 0
- case infExp:
- if x.neg {
- return nil, Above
- }
- return nil, Below
- case nanExp:
- return nil, Undef
+ switch x.form {
+ case finite:
+ // 0 < |x| < +Inf
+ acc := x.cmpZero()
+ if x.exp <= 0 {
+ // 0 < |x| < 1
+ return z.SetInt64(0), acc
}
- panic("unreachable")
- }
+ // x.exp > 0
- // 0 < |x| < +Inf
- acc := Below
- if x.neg {
- acc = Above
- }
- if x.exp <= 0 {
- // 0 < |x| < 1
- return z.SetInt64(0), acc
- }
- // x.exp > 0
+ // 1 <= |x| < +Inf
+ // determine minimum required precision for x
+ allBits := uint(len(x.mant)) * _W
+ exp := uint(x.exp)
+ if x.MinPrec() <= exp {
+ acc = Exact
+ }
+ // shift mantissa as needed
+ if z == nil {
+ z = new(Int)
+ }
+ z.neg = x.neg
+ switch {
+ case exp > allBits:
+ z.abs = z.abs.shl(x.mant, exp-allBits)
+ default:
+ z.abs = z.abs.set(x.mant)
+ case exp < allBits:
+ z.abs = z.abs.shr(x.mant, allBits-exp)
+ }
+ return z, acc
- // 1 <= |x| < +Inf
- // determine minimum required precision for x
- allBits := uint(len(x.mant)) * _W
- exp := uint(x.exp)
- if x.MinPrec() <= exp {
- acc = Exact
- }
- // shift mantissa as needed
- if z == nil {
- z = new(Int)
- }
- z.neg = x.neg
- switch {
- case exp > allBits:
- z.abs = z.abs.shl(x.mant, exp-allBits)
- default:
- z.abs = z.abs.set(x.mant)
- case exp < allBits:
- z.abs = z.abs.shr(x.mant, allBits-exp)
+ case zero:
+ return z.SetInt64(0), Exact
+
+ case inf:
+ return nil, x.cmpZero()
+
+ case nan:
+ return nil, Undef
}
- return z, acc
+
+ panic("unreachable")
}
// Rat returns the rational number corresponding to x;
x.validate()
}
- if z == nil {
- // no need to do this for Inf and NaN
- // but those are rare enough that we
- // don't care
+ if z == nil && x.form <= finite {
z = new(Rat)
}
- // special cases
- if len(x.mant) == 0 {
- switch x.exp {
- case 0:
- return z.SetInt64(0), Exact // 0
- case infExp:
- if x.neg {
- return nil, Above
- }
- return nil, Below
- case nanExp:
- return nil, Undef
+ switch x.form {
+ case finite:
+ // 0 < |x| < +Inf
+ allBits := int32(len(x.mant)) * _W
+ // build up numerator and denominator
+ 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)
+ // 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)
+ // 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))
+ z.norm()
}
- panic("unreachable")
+ return z, Exact
+
+ case zero:
+ return z.SetInt64(0), Exact
+
+ case inf:
+ return nil, x.cmpZero()
+
+ case nan:
+ return nil, Undef
}
- // 0 <= |x| < Inf
- allBits := int32(len(x.mant)) * _W
- // build up numerator and denominator
- 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)
- // 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)
- // 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))
- z.norm()
- }
- return z, Exact
+ panic("unreachable")
}
// Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
// http://www.vinc17.net/research/papers/rnc6.pdf
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
- panic("uadd called with 0 argument")
+ panic("uadd called with empty mantissa")
}
// compute exponents ex, ey for mantissa with "binary point"
// by special-casing, and the code will diverge.
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
- panic("usub called with 0 argument")
+ panic("usub called with empty mantissa")
}
ex := int64(x.exp) - int64(len(x.mant))*_W
// operands may have cancelled each other out
if len(z.mant) == 0 {
z.acc = Exact
- z.setZero()
+ z.form = zero
return
}
// len(z.mant) > 0
// x and y must not be 0, Inf, or NaN.
func (z *Float) umul(x, y *Float) {
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
- panic("umul called with 0 argument")
+ panic("umul called with empty mantissa")
}
// Note: This is doing too much work if the precision
// x and y must not be 0, Inf, or NaN.
func (z *Float) uquo(x, y *Float) {
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
- panic("uquo called with 0 argument")
+ panic("uquo called with empty mantissa")
}
// mantissa length in words for desired result precision + 1
// while ignoring the signs of x and y. x and y must not be 0, Inf, or NaN.
func (x *Float) ucmp(y *Float) int {
if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
- panic("ucmp called with 0 argument")
+ panic("ucmp called with empty mantissa")
}
switch {
}
// special cases
- if len(x.mant) == 0 || len(y.mant) == 0 {
- if x.exp <= infExp || y.exp <= infExp {
+ if x.form != finite || y.form != finite {
+ if x.form > finite || y.form > finite {
// TODO(gri) handle Inf separately
return z.SetNaN()
}
- if len(x.mant) == 0 { // x == ±0
+ if x.form == zero {
z.Set(y)
- if len(z.mant) == 0 && z.exp == 0 {
+ if z.form == zero {
z.neg = x.neg && y.neg // -0 + -0 == -0
}
return z
}
// x, y != 0
+ z.form = finite
z.neg = x.neg
if x.neg == y.neg {
// x + y == x + y
}
// -0 is only possible for -0 + -0
- if len(z.mant) == 0 {
+ if z.form == zero {
z.neg = false
}
}
// special cases
- if len(x.mant) == 0 || len(y.mant) == 0 {
- if x.exp <= infExp || y.exp <= infExp {
+ if x.form != finite || y.form != finite {
+ if x.form > finite || y.form > finite {
// TODO(gri) handle Inf separately
return z.SetNaN()
}
- if len(x.mant) == 0 { // x == ±0
+ if x.form == zero {
z.Neg(y)
- if len(z.mant) == 0 && z.exp == 0 {
+ if z.form == zero {
z.neg = x.neg && !y.neg // -0 - 0 == -0
}
return z
}
// x, y != 0
+ z.form = finite
z.neg = x.neg
if x.neg != y.neg {
// x - (-y) == x + y
}
// -0 is only possible for -0 - 0
- if len(z.mant) == 0 {
+ if z.form == zero {
z.neg = false
}
z.neg = x.neg != y.neg
// special cases
- if len(x.mant) == 0 || len(y.mant) == 0 {
- if x.exp <= infExp || y.exp <= infExp {
+ if x.form != finite || y.form != finite {
+ if x.form > finite || y.form > finite {
// TODO(gri) handle Inf separately
return z.SetNaN()
}
// x == ±0 || y == ±0
z.acc = Exact
- z.setZero()
+ z.form = zero
return z
}
- if len(x.mant) == 0 || len(y.mant) == 0 {
+ if x.form == zero || y.form == zero {
z.acc = Exact
- z.setZero()
+ z.form = zero
return z
}
// x, y != 0
+ z.form = finite
z.umul(x, y)
return z
}
// special cases
z.acc = Exact
- if len(x.mant) == 0 || len(y.mant) == 0 {
- if x.exp <= infExp || y.exp <= infExp {
+ if x.form != finite || y.form != finite {
+ if x.form > finite || y.form > finite {
// TODO(gri) handle Inf separately
return z.SetNaN()
}
- if len(x.mant) == 0 {
- if len(y.mant) == 0 {
+ if x.form == zero {
+ if y.form == zero {
return z.SetNaN()
}
- z.setZero()
+ z.form = zero
return z
}
// x != 0
- if len(y.mant) == 0 {
- z.setInf()
+ if y.form == zero {
+ z.form = inf
return z
}
}
// x, y != 0
+ z.form = finite
z.uquo(x, y)
return z
}
// +2 if x == +Inf
//
func (x *Float) ord() int {
- m := 1 // common case
- if len(x.mant) == 0 {
- m = 0
- if x.exp == infExp {
- m = 2
- }
- if x.exp == nanExp {
- panic("unimplemented")
- }
+ var m int
+ switch x.form {
+ case finite:
+ m = 1
+ case zero:
+ return 0
+ case inf:
+ m = 2
+ case nan:
+ panic("unimplemented")
}
if x.neg {
m = -m