]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: remove NaN support - just not worth it
authorRobert Griesemer <gri@golang.org>
Tue, 31 Mar 2015 01:11:48 +0000 (18:11 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 31 Mar 2015 23:05:31 +0000 (23:05 +0000)
NaNs make the API more complicated for no real good reasons.
There are few operations that produce NaNs with IEEE arithmetic,
there's no need to copy the behavior. It's easy to test for these
scenarios and avoid them (on the other hand, it's not easy to test
for overflow or underflow, so we want to keep +/-Inf).

Also:
- renamed IsNeg -> Signbit (clearer, especially for x == -0)
- removed IsZero           (Sign() == 0 is sufficient and efficient)
- removed IsFinite         (now same as !IsInf)

Change-Id: I3f3b4445c325d9bbb1bf46ce2e298a6aeb498e07
Reviewed-on: https://go-review.googlesource.com/8280
Reviewed-by: Alan Donovan <adonovan@google.com>
src/math/big/accuracy_string.go
src/math/big/float.go
src/math/big/float_test.go
src/math/big/floatconv.go
src/math/big/floatconv_test.go
src/math/big/floatexample_test.go
src/math/big/ftoa.go

index 647a1fb6d31cc6f9d7aa0623f81695e9ac9069df..24ef7f10770026a6199ed4218c27c12783da3054 100644 (file)
@@ -4,13 +4,14 @@ package big
 
 import "fmt"
 
-const _Accuracy_name = "ExactBelowAboveUndef"
+const _Accuracy_name = "BelowExactAbove"
 
-var _Accuracy_index = [...]uint8{0, 5, 10, 15, 20}
+var _Accuracy_index = [...]uint8{0, 5, 10, 15}
 
 func (i Accuracy) String() string {
+       i -= -1
        if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) {
-               return fmt.Sprintf("Accuracy(%d)", i)
+               return fmt.Sprintf("Accuracy(%d)", i+-1)
        }
        return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
 }
index 629510a18e6bc0a3b1ebe52246d94a0606e83454..2e536e04ad738e1a1eb30243898a1ec41242ba82 100644 (file)
@@ -23,10 +23,9 @@ const debugFloat = true // enable for debugging
 //   sign × mantissa × 2**exponent
 //
 // 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). 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.
+// A Float may also be zero (+0, -0) or infinite (+Inf, -Inf).
+// All Floats are ordered, and the ordering of two Floats x and y
+// is defined by x.Cmp(y).
 //
 // Each Float value also has a precision, rounding mode, and accuracy.
 // The precision is the maximum number of mantissa bits available to
@@ -34,10 +33,10 @@ const debugFloat = true // enable for debugging
 // be rounded to fit into the mantissa bits, and accuracy describes the
 // rounding error with respect to the exact result.
 //
-// All operations, including setters, that specify a *Float variable for
-// the result (usually via the receiver with the exception of MantExp),
-// round the numeric result according to the precision and rounding mode
-// of the result variable, unless specified otherwise.
+// Unless specified otherwise, all operations (including setters) that
+// specify a *Float variable for the result (usually via the receiver
+// with the exception of MantExp), round the numeric result according
+// to the precision and rounding mode of the result variable.
 //
 // If the provided result precision is 0 (see below), it is set to the
 // precision of the argument with the largest precision value before any
@@ -48,9 +47,10 @@ const debugFloat = true // enable for debugging
 //
 // By setting the desired precision to 24 or 53 and using matching rounding
 // mode (typically ToNearestEven), Float operations produce the same results
-// as the corresponding float32 or float64 IEEE-754 arithmetic. Exponent
-// underflow and overflow lead to a 0 or an Infinity for different values
-// than IEEE-754 because Float exponents have a much larger range.
+// as the corresponding float32 or float64 IEEE-754 arithmetic for operands
+// that correspond to normal (i.e., not denormal) float32 or float64 numbers.
+// Exponent underflow and overflow lead to a 0 or an Infinity for different
+// values than IEEE-754 because Float exponents have a much larger range.
 //
 // The zero (uninitialized) value for a Float is ready to use and represents
 // the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven.
@@ -65,9 +65,19 @@ type Float struct {
        exp  int32
 }
 
+// Float operations that would lead to a NaN under IEEE-754 rules cause
+// a run-time panic of ErrNaN type.
+type ErrNaN struct {
+       msg string
+}
+
 // NewFloat allocates and returns a new Float set to x,
 // with precision 53 and rounding mode ToNearestEven.
+// NewFloat panics with ErrNan if x is a NaN.
 func NewFloat(x float64) *Float {
+       if math.IsNaN(x) {
+               panic(ErrNaN{"NewFloat(NaN)"})
+       }
        return new(Float).SetFloat64(x)
 }
 
@@ -87,15 +97,13 @@ const (
 // 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.
+// A zero or non-finite Float x ignores x.mant and x.exp.
 //
 // 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
@@ -105,7 +113,6 @@ const (
        zero form = iota
        finite
        inf
-       nan
 )
 
 // RoundingMode determines how a Float value is rounded to the
@@ -127,16 +134,13 @@ const (
 
 // Accuracy describes the rounding error produced by the most recent
 // operation that generated a Float value, relative to the exact value.
-// The accuracy is Undef for operations on and resulting in NaNs since
-// they are neither Below nor Above any other value.
-type Accuracy byte
+type Accuracy int8
 
 // Constants describing the Accuracy of a Float.
 const (
+       Below Accuracy = -1
        Exact Accuracy = 0
-       Below Accuracy = 1 << 0
-       Above Accuracy = 1 << 1
-       Undef Accuracy = Below | Above
+       Above Accuracy = +1
 )
 
 //go:generate stringer -type=Accuracy
@@ -144,8 +148,8 @@ const (
 // 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.
-// SetPrec(0) maps all finite values to ±0; infinite and NaN values remain
-// unchanged. If prec > MaxPrec, it is set to MaxPrec.
+// SetPrec(0) maps all finite values to ±0; infinite values remain unchanged.
+// If prec > MaxPrec, it is set to MaxPrec.
 func (z *Float) SetPrec(prec uint) *Float {
        z.acc = Exact // optimistically assume no rounding is needed
 
@@ -189,14 +193,14 @@ func (z *Float) SetMode(mode RoundingMode) *Float {
 }
 
 // Prec returns the mantissa precision of x in bits.
-// The result may be 0 for |x| == 0, |x| == Inf, or NaN.
+// The result may be 0 for |x| == 0 and |x| == Inf.
 func (x *Float) Prec() uint {
        return uint(x.prec)
 }
 
 // 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 if x is 0 or not finite.
+// The result is 0 for |x| == 0 and |x| == Inf.
 func (x *Float) MinPrec() uint {
        if x.form != finite {
                return 0
@@ -217,14 +221,14 @@ func (x *Float) Acc() Accuracy {
 // Sign returns:
 //
 //     -1 if x <   0
-//      0 if x is ±0 or NaN
+//      0 if x is ±0
 //     +1 if x >   0
 //
 func (x *Float) Sign() int {
        if debugFloat {
                x.validate()
        }
-       if x.form == zero || x.form == nan {
+       if x.form == zero {
                return 0
        }
        if x.neg {
@@ -245,7 +249,6 @@ func (x *Float) Sign() int {
 //
 //     (  ±0).MantExp(mant) = 0, with mant set to   ±0
 //     (±Inf).MantExp(mant) = 0, with mant set to ±Inf
-//     ( NaN).MantExp(mant) = 0, with mant set to  NaN
 //
 // x and mant may be the same in which case x is set to its
 // mantissa value.
@@ -297,7 +300,6 @@ func (z *Float) setExpAndRound(exp int64, sbit uint) {
 //
 //     z.SetMantExp(  ±0, exp) =   ±0
 //     z.SetMantExp(±Inf, exp) = ±Inf
-//     z.SetMantExp( NaN, exp) =  NaN
 //
 // z and mant may be the same in which case z's exponent
 // is set to exp.
@@ -314,21 +316,9 @@ func (z *Float) SetMantExp(mant *Float, exp int) *Float {
        return z
 }
 
-// IsNeg reports whether x is negative.
-// A NaN value is not negative.
-func (x *Float) IsNeg() bool {
-       return x.neg && x.form != nan
-}
-
-// IsZero reports whether x is +0 or -0.
-func (x *Float) IsZero() bool {
-       return x.form == zero
-}
-
-// IsFinite reports whether -Inf < x < Inf.
-// A NaN value is not finite.
-func (x *Float) IsFinite() bool {
-       return x.form <= finite
+// Signbit returns true if x is negative or negative zero.
+func (x *Float) Signbit() bool {
+       return x.neg
 }
 
 // IsInf reports whether x is +Inf or -Inf.
@@ -336,13 +326,8 @@ func (x *Float) IsInf() bool {
        return x.form == inf
 }
 
-// IsNaN reports whether x is a NaN value.
-func (x *Float) IsNaN() bool {
-       return x.form == nan
-}
-
 // IsInt reports whether x is an integer.
-// ±Inf and NaN values are not integers.
+// ±Inf values are not integers.
 func (x *Float) IsInt() bool {
        if debugFloat {
                x.validate()
@@ -526,7 +511,7 @@ func (z *Float) round(sbit uint) {
 
        // update accuracy
        if z.acc != Exact && z.neg {
-               z.acc ^= Below | Above
+               z.acc = -z.acc
        }
 
        if debugFloat {
@@ -598,13 +583,13 @@ func (z *Float) SetInt64(x int64) *Float {
 
 // SetFloat64 sets z to the (possibly rounded) value of x and returns z.
 // If z's precision is 0, it is changed to 53 (and rounding will have
-// no effect).
+// no effect). SetFloat64 panics with ErrNaN if x is a NaN.
 func (z *Float) SetFloat64(x float64) *Float {
        if z.prec == 0 {
                z.prec = 53
        }
        if math.IsNaN(x) {
-               return z.SetNaN()
+               panic(ErrNaN{"Float.SetFloat64(NaN)"})
        }
        z.acc = Exact
        z.neg = math.Signbit(x) // handle -0, -Inf correctly
@@ -684,21 +669,14 @@ func (z *Float) SetRat(x *Rat) *Float {
        return z.Quo(&a, &b)
 }
 
-// SetInf sets z to the infinite Float +Inf for sign >= 0,
-// or -Inf for sign < 0, and returns z. The precision of
-// z is unchanged and the result is always Exact.
-func (z *Float) SetInf(sign int) *Float {
+// SetInf sets z to the infinite Float -Inf if signbit is
+// set, or +Inf if signbit is not set, and returns z. The
+// precision of z is unchanged and the result is always
+// Exact.
+func (z *Float) SetInf(signbit bool) *Float {
        z.acc = Exact
        z.form = inf
-       z.neg = sign < 0
-       return z
-}
-
-// SetNaN sets z to a NaN value, and returns z.
-// The precision of z is unchanged and the result accuracy is always Undef.
-func (z *Float) SetNaN() *Float {
-       z.acc = Undef
-       z.form = nan
+       z.neg = signbit
        return z
 }
 
@@ -774,8 +752,8 @@ func high64(x nat) uint64 {
 // Uint64 returns the unsigned integer resulting from truncating x
 // towards zero. If 0 <= x <= math.MaxUint64, the result is Exact
 // if x is an integer and Below otherwise.
-// The result is (0, Above) for x < 0, (math.MaxUint64, Below)
-// for x > math.MaxUint64, and (0, Undef) for NaNs.
+// The result is (0, Above) for x < 0, and (math.MaxUint64, Below)
+// for x > math.MaxUint64.
 func (x *Float) Uint64() (uint64, Accuracy) {
        if debugFloat {
                x.validate()
@@ -811,9 +789,6 @@ func (x *Float) Uint64() (uint64, Accuracy) {
                        return 0, Above
                }
                return math.MaxUint64, Below
-
-       case nan:
-               return 0, Undef
        }
 
        panic("unreachable")
@@ -823,7 +798,7 @@ func (x *Float) Uint64() (uint64, Accuracy) {
 // If math.MinInt64 <= x <= math.MaxInt64, the result is Exact if x is
 // an integer, and Above (x < 0) or Below (x > 0) otherwise.
 // The result is (math.MinInt64, Above) for x < math.MinInt64,
-// (math.MaxInt64, Below) for x > math.MaxInt64, and (0, Undef) for NaNs.
+// and (math.MaxInt64, Below) for x > math.MaxInt64.
 func (x *Float) Int64() (int64, Accuracy) {
        if debugFloat {
                x.validate()
@@ -869,9 +844,6 @@ func (x *Float) Int64() (int64, Accuracy) {
                        return math.MinInt64, Above
                }
                return math.MaxInt64, Below
-
-       case nan:
-               return 0, Undef
        }
 
        panic("unreachable")
@@ -885,7 +857,6 @@ func (x *Float) Int64() (int64, Accuracy) {
 // is (0, Below) or (-0, Above), respectively, depending on the sign of x.
 // If x is too large to be represented by a float32 (|x| > math.MaxFloat32),
 // the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
-// The result is (NaN, Undef) for NaNs.
 func (x *Float) Float32() (float32, Accuracy) {
        if debugFloat {
                x.validate()
@@ -976,9 +947,6 @@ func (x *Float) Float32() (float32, Accuracy) {
                        return float32(math.Inf(-1)), Exact
                }
                return float32(math.Inf(+1)), Exact
-
-       case nan:
-               return float32(math.NaN()), Undef
        }
 
        panic("unreachable")
@@ -989,7 +957,6 @@ func (x *Float) Float32() (float32, Accuracy) {
 // is (0, Below) or (-0, Above), respectively, depending on the sign of x.
 // If x is too large to be represented by a float64 (|x| > math.MaxFloat64),
 // the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
-// The result is (NaN, Undef) for NaNs.
 func (x *Float) Float64() (float64, Accuracy) {
        if debugFloat {
                x.validate()
@@ -1080,16 +1047,13 @@ func (x *Float) Float64() (float64, Accuracy) {
                        return math.Inf(-1), Exact
                }
                return math.Inf(+1), Exact
-
-       case nan:
-               return math.NaN(), Undef
        }
 
        panic("unreachable")
 }
 
 // Int returns the result of truncating x towards zero;
-// or nil if x is an infinity or NaN.
+// 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.
 // If a non-nil *Int argument z is provided, Int stores
@@ -1140,17 +1104,14 @@ func (x *Float) Int(z *Int) (*Int, Accuracy) {
 
        case inf:
                return nil, makeAcc(x.neg)
-
-       case nan:
-               return nil, Undef
        }
 
        panic("unreachable")
 }
 
 // Rat returns the rational number corresponding to x;
-// or nil if x is an infinity or NaN.
-// The result is Exact is x is not an Inf or NaN.
+// or nil if x is an infinity.
+// The result is Exact is x is not an Inf.
 // If a non-nil *Rat argument z is provided, Rat stores
 // the result in z instead of allocating a new Rat.
 func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
@@ -1190,9 +1151,6 @@ func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
 
        case inf:
                return nil, makeAcc(x.neg)
-
-       case nan:
-               return nil, Undef
        }
 
        panic("unreachable")
@@ -1379,19 +1337,19 @@ func (z *Float) uquo(x, y *Float) {
        z.setExpAndRound(e-fnorm(z.mant), sbit)
 }
 
-// ucmp returns Below, Exact, or Above, depending
-// on whether |x| < |y|, |x| == |y|, or |x| > |y|.
+// ucmp returns -1, 0, or +1, depending on whether
+// |x| < |y|, |x| == |y|, or |x| > |y|.
 // x and y must have a non-empty mantissa and valid exponent.
-func (x *Float) ucmp(y *Float) Accuracy {
+func (x *Float) ucmp(y *Float) int {
        if debugFloat {
                validateBinaryOperands(x, y)
        }
 
        switch {
        case x.exp < y.exp:
-               return Below
+               return -1
        case x.exp > y.exp:
-               return Above
+               return +1
        }
        // x.exp == y.exp
 
@@ -1410,13 +1368,13 @@ func (x *Float) ucmp(y *Float) Accuracy {
                }
                switch {
                case xm < ym:
-                       return Below
+                       return -1
                case xm > ym:
-                       return Above
+                       return +1
                }
        }
 
-       return Exact
+       return 0
 }
 
 // Handling of sign bit as defined by IEEE 754-2008, section 6.3:
@@ -1443,7 +1401,7 @@ func (x *Float) ucmp(y *Float) Accuracy {
 // Rounding is performed according to z's precision and rounding mode; and
 // z's accuracy reports the result error relative to the exact (not rounded)
 // result.
-// BUG(gri) Float.Add returns NaN if an operand is Inf.
+// BUG(gri) Float.Add panics if an operand is Inf.
 // BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
 func (z *Float) Add(x, y *Float) *Float {
        if debugFloat {
@@ -1459,7 +1417,7 @@ func (z *Float) Add(x, y *Float) *Float {
        if x.form != finite || y.form != finite {
                if x.form > finite || y.form > finite {
                        // TODO(gri) handle Inf separately
-                       return z.SetNaN()
+                       panic("Inf operand")
                }
                if x.form == zero {
                        z.Set(y)
@@ -1481,7 +1439,7 @@ func (z *Float) Add(x, y *Float) *Float {
        } else {
                // x + (-y) == x - y == -(y - x)
                // (-x) + y == y - x == -(x - y)
-               if x.ucmp(y) == Above {
+               if x.ucmp(y) > 0 {
                        z.usub(x, y)
                } else {
                        z.neg = !z.neg
@@ -1494,7 +1452,7 @@ func (z *Float) Add(x, y *Float) *Float {
 
 // Sub sets z to the rounded difference x-y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
-// BUG(gri) Float.Sub returns NaN if an operand is Inf.
+// BUG(gri) Float.Sub panics if an operand is Inf.
 func (z *Float) Sub(x, y *Float) *Float {
        if debugFloat {
                x.validate()
@@ -1509,7 +1467,7 @@ func (z *Float) Sub(x, y *Float) *Float {
        if x.form != finite || y.form != finite {
                if x.form > finite || y.form > finite {
                        // TODO(gri) handle Inf separately
-                       return z.SetNaN()
+                       panic("Inf operand")
                }
                if x.form == zero {
                        z.Neg(y)
@@ -1531,7 +1489,7 @@ func (z *Float) Sub(x, y *Float) *Float {
        } else {
                // x - y == x - y == -(y - x)
                // (-x) - (-y) == y - x == -(x - y)
-               if x.ucmp(y) == Above {
+               if x.ucmp(y) > 0 {
                        z.usub(x, y)
                } else {
                        z.neg = !z.neg
@@ -1544,7 +1502,7 @@ func (z *Float) Sub(x, y *Float) *Float {
 
 // Mul sets z to the rounded product x*y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
-// BUG(gri) Float.Mul returns NaN if an operand is Inf.
+// BUG(gri) Float.Mul panics if an operand is Inf.
 func (z *Float) Mul(x, y *Float) *Float {
        if debugFloat {
                x.validate()
@@ -1561,7 +1519,7 @@ func (z *Float) Mul(x, y *Float) *Float {
        if x.form != finite || y.form != finite {
                if x.form > finite || y.form > finite {
                        // TODO(gri) handle Inf separately
-                       return z.SetNaN()
+                       panic("Inf operand")
                }
                // x == ±0 || y == ±0
                z.acc = Exact
@@ -1577,7 +1535,8 @@ func (z *Float) Mul(x, y *Float) *Float {
 
 // Quo sets z to the rounded quotient x/y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
-// BUG(gri) Float.Quo returns NaN if an operand is Inf.
+// Quo panics is both operands are 0.
+// BUG(gri) Float.Quo panics if an operand is Inf.
 func (z *Float) Quo(x, y *Float) *Float {
        if debugFloat {
                x.validate()
@@ -1595,12 +1554,12 @@ func (z *Float) Quo(x, y *Float) *Float {
        if x.form != finite || y.form != finite {
                if x.form > finite || y.form > finite {
                        // TODO(gri) handle Inf separately
-                       return z.SetNaN()
+                       panic("Inf operand")
                }
                // x == ±0 || y == ±0
                if x.form == zero {
                        if y.form == zero {
-                               return z.SetNaN()
+                               panic("0/0")
                        }
                        z.form = zero
                        return z
@@ -1616,57 +1575,39 @@ func (z *Float) Quo(x, y *Float) *Float {
        return z
 }
 
-type cmpResult struct {
-       acc Accuracy
-}
-
 // Cmp compares x and y and returns:
 //
-//   Below if x <  y
-//   Exact if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
-//   Above if x >  y
-//   Undef if any of x, y is NaN
+//   -1 if x <  y
+//    0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
+//   +1 if x >  y
 //
-func (x *Float) Cmp(y *Float) cmpResult {
+func (x *Float) Cmp(y *Float) int {
        if debugFloat {
                x.validate()
                y.validate()
        }
 
-       if x.form == nan || y.form == nan {
-               return cmpResult{Undef}
-       }
-
        mx := x.ord()
        my := y.ord()
        switch {
        case mx < my:
-               return cmpResult{Below}
+               return -1
        case mx > my:
-               return cmpResult{Above}
+               return +1
        }
        // mx == my
 
        // only if |mx| == 1 we have to compare the mantissae
        switch mx {
        case -1:
-               return cmpResult{y.ucmp(x)}
+               return y.ucmp(x)
        case +1:
-               return cmpResult{x.ucmp(y)}
+               return x.ucmp(y)
        }
 
-       return cmpResult{Exact}
+       return 0
 }
 
-// The following accessors simplify testing of Cmp results.
-func (res cmpResult) Acc() Accuracy { return res.acc }
-func (res cmpResult) Eql() bool     { return res.acc == Exact }
-func (res cmpResult) Neq() bool     { return res.acc != Exact }
-func (res cmpResult) Lss() bool     { return res.acc == Below }
-func (res cmpResult) Leq() bool     { return res.acc&Above == 0 }
-func (res cmpResult) Gtr() bool     { return res.acc == Above }
-func (res cmpResult) Geq() bool     { return res.acc&Below == 0 }
-
 // ord classifies x and returns:
 //
 //     -2 if -Inf == x
@@ -1675,7 +1616,6 @@ func (res cmpResult) Geq() bool     { return res.acc&Below == 0 }
 //     +1 if 0 < x < +Inf
 //     +2 if x == +Inf
 //
-// x must not be NaN.
 func (x *Float) ord() int {
        var m int
        switch x.form {
@@ -1685,8 +1625,6 @@ func (x *Float) ord() int {
                return 0
        case inf:
                m = 2
-       default:
-               panic("unreachable")
        }
        if x.neg {
                m = -m
index 9d101531de871352062570e187ed5138b9312849..b3f1a60474599902039c7f0bc6f33b31496e02e8 100644 (file)
@@ -69,7 +69,7 @@ func TestFloatZeroValue(t *testing.T) {
                {1, 2, 0, 0, '*', (*Float).Mul},
                {2, 0, 1, 0, '*', (*Float).Mul},
 
-               {0, 0, 0, 0, '/', (*Float).Quo}, // = Nan
+               // {0, 0, 0, 0, '/', (*Float).Quo}, // panics
                {0, 2, 1, 2, '/', (*Float).Quo},
                {1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf
                {2, 0, 1, 0, '/', (*Float).Quo},
@@ -77,7 +77,7 @@ func TestFloatZeroValue(t *testing.T) {
                z := make(test.z)
                test.op(z, make(test.x), make(test.y))
                got := 0
-               if z.IsFinite() {
+               if !z.IsInf() {
                        got = int(z.int64())
                }
                if got != test.want {
@@ -97,11 +97,9 @@ func makeFloat(s string) *Float {
        case "-0":
                return x.Neg(&x)
        case "Inf", "+Inf":
-               return x.SetInf(+1)
+               return x.SetInf(false)
        case "-Inf":
-               return x.SetInf(-1)
-       case "NaN", "-NaN":
-               return x.SetNaN()
+               return x.SetInf(true)
        }
 
        x.SetPrec(1000)
@@ -123,7 +121,6 @@ func TestFloatSetPrec(t *testing.T) {
                {"-0", 0, "-0", Exact},
                {"-Inf", 0, "-Inf", Exact},
                {"+Inf", 0, "+Inf", Exact},
-               {"NaN", 0, "NaN", Exact},
                {"123", 0, "0", Below},
                {"-123", 0, "-0", Above},
 
@@ -132,7 +129,6 @@ func TestFloatSetPrec(t *testing.T) {
                {"-0", MaxPrec, "-0", Exact},
                {"-Inf", MaxPrec, "-Inf", Exact},
                {"+Inf", MaxPrec, "+Inf", Exact},
-               {"NaN", MaxPrec, "NaN", Exact},
 
                // just a few regular cases - general rounding is tested elsewhere
                {"1.5", 1, "2", Above},
@@ -164,7 +160,6 @@ func TestFloatMinPrec(t *testing.T) {
                {"-0", 0},
                {"+Inf", 0},
                {"-Inf", 0},
-               {"NaN", 0},
                {"1", 1},
                {"2", 1},
                {"3", 2},
@@ -191,7 +186,6 @@ func TestFloatSign(t *testing.T) {
                {"+0", 0},
                {"+1", +1},
                {"+Inf", +1},
-               {"NaN", 0},
        } {
                x := makeFloat(test.x)
                s := x.Sign()
@@ -201,13 +195,9 @@ func TestFloatSign(t *testing.T) {
        }
 }
 
-// feq(x, y) is like x.Cmp(y) == 0 but it also considers the sign of 0 (0 != -0).
-// Caution: Two NaN's are equal with this function!
-func feq(x, y *Float) bool {
-       if x.IsNaN() || y.IsNaN() {
-               return x.IsNaN() && y.IsNaN()
-       }
-       return x.Cmp(y).Eql() && x.IsNeg() == y.IsNeg()
+// alike(x, y) is like x.Cmp(y) == 0 but also considers the sign of 0 (0 != -0).
+func alike(x, y *Float) bool {
+       return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
 }
 
 func TestFloatMantExp(t *testing.T) {
@@ -222,7 +212,6 @@ func TestFloatMantExp(t *testing.T) {
                {"Inf", "+Inf", 0},
                {"+Inf", "+Inf", 0},
                {"-Inf", "-Inf", 0},
-               {"NaN", "NaN", 0},
                {"1.5", "0.75", 1},
                {"1.024e3", "0.5", 11},
                {"-0.125", "-0.5", -2},
@@ -231,7 +220,7 @@ func TestFloatMantExp(t *testing.T) {
                mant := makeFloat(test.mant)
                m := new(Float)
                e := x.MantExp(m)
-               if !feq(m, mant) || e != test.exp {
+               if !alike(m, mant) || e != test.exp {
                        t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, m.Format('g', 10), e, test.mant, test.exp)
                }
        }
@@ -242,7 +231,7 @@ func TestFloatMantExpAliasing(t *testing.T) {
        if e := x.MantExp(x); e != 10 {
                t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e)
        }
-       if want := makeFloat("0.5"); !feq(x, want) {
+       if want := makeFloat("0.5"); !alike(x, want) {
                t.Fatalf("Float.MantExp aliasing error: got %s; want %s", x.Format('g', 10), want.Format('g', 10))
        }
 }
@@ -274,12 +263,12 @@ func TestFloatSetMantExp(t *testing.T) {
                want := makeFloat(test.z)
                var z Float
                z.SetMantExp(frac, test.exp)
-               if !feq(&z, want) {
+               if !alike(&z, want) {
                        t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Format('g', 10), test.z)
                }
                // test inverse property
                mant := new(Float)
-               if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want).Neq() {
+               if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 {
                        t.Errorf("Inverse property not satisfied: got %s; want %s", z.Format('g', 10), test.z)
                }
        }
@@ -287,33 +276,27 @@ func TestFloatSetMantExp(t *testing.T) {
 
 func TestFloatPredicates(t *testing.T) {
        for _, test := range []struct {
-               x                           string
-               neg, zero, finite, inf, nan bool
+               x            string
+               sign         int
+               signbit, inf bool
        }{
-               {x: "-Inf", neg: true, inf: true},
-               {x: "-1", neg: true, finite: true},
-               {x: "-0", neg: true, zero: true, finite: true},
-               {x: "0", zero: true, finite: true},
-               {x: "1", finite: true},
-               {x: "+Inf", inf: true},
-               {x: "NaN", nan: true},
+               {x: "-Inf", sign: -1, signbit: true, inf: true},
+               {x: "-1", sign: -1, signbit: true},
+               {x: "-0", signbit: true},
+               {x: "0"},
+               {x: "1", sign: 1},
+               {x: "+Inf", sign: 1, inf: true},
        } {
                x := makeFloat(test.x)
-               if got := x.IsNeg(); got != test.neg {
-                       t.Errorf("(%s).IsNeg() = %v; want %v", test.x, got, test.neg)
-               }
-               if got := x.IsZero(); got != test.zero {
-                       t.Errorf("(%s).IsZero() = %v; want %v", test.x, got, test.zero)
+               if got := x.Signbit(); got != test.signbit {
+                       t.Errorf("(%s).Signbit() = %v; want %v", test.x, got, test.signbit)
                }
-               if got := x.IsFinite(); got != test.finite {
-                       t.Errorf("(%s).IsFinite() = %v; want %v", test.x, got, test.finite)
+               if got := x.Sign(); got != test.sign {
+                       t.Errorf("(%s).Sign() = %d; want %d", test.x, got, test.sign)
                }
                if got := x.IsInf(); got != test.inf {
                        t.Errorf("(%s).IsInf() = %v; want %v", test.x, got, test.inf)
                }
-               if got := x.IsNaN(); got != test.nan {
-                       t.Errorf("(%s).IsNaN() = %v; want %v", test.x, got, test.nan)
-               }
        }
 }
 
@@ -333,7 +316,6 @@ func TestFloatIsInt(t *testing.T) {
                "Inf",
                "+Inf",
                "-Inf",
-               "NaN",
        } {
                s := strings.TrimSuffix(test, " int")
                want := s != test
@@ -413,7 +395,7 @@ func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
        // should be the same as rounding by SetInt64 after setting the
        // precision)
        g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
-       if !feq(g, f) {
+       if !alike(g, f) {
                t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s",
                        toBinary(x), prec, mode,
                        toBinary(g.int64()),
@@ -426,7 +408,7 @@ func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
        // h and f should be the same
        // (repeated rounding should be idempotent)
        h := new(Float).SetMode(mode).SetPrec(prec).Set(f)
-       if !feq(h, f) {
+       if !alike(h, f) {
                t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s",
                        toBinary(x), prec, mode,
                        toBinary(h.int64()),
@@ -647,13 +629,6 @@ func TestFloatSetFloat64(t *testing.T) {
                }
        }
 
-       // test NaN
-       var f Float
-       f.SetFloat64(math.NaN())
-       if got, acc := f.Float64(); !math.IsNaN(got) || acc != Undef {
-               t.Errorf("got %g (%s, %s); want %g (undef)", got, f.Format('p', 0), acc, math.NaN())
-       }
-
        // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
        const x uint64 = 0x8765432143218 // 53 bits needed
        for prec := uint(1); prec <= 52; prec++ {
@@ -664,6 +639,17 @@ func TestFloatSetFloat64(t *testing.T) {
                        t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
                }
        }
+
+       // test NaN
+       defer func() {
+               if p, ok := recover().(ErrNaN); !ok {
+                       t.Errorf("got %v; want ErrNaN panic", p)
+               }
+       }()
+       var f Float
+       f.SetFloat64(math.NaN())
+       // should not reach here
+       t.Errorf("got %s; want ErrNaN panic", f.Format('p', 0))
 }
 
 func TestFloatSetInt(t *testing.T) {
@@ -747,20 +733,18 @@ func TestFloatSetRat(t *testing.T) {
 func TestFloatSetInf(t *testing.T) {
        var f Float
        for _, test := range []struct {
-               sign int
-               prec uint
-               want string
+               signbit bool
+               prec    uint
+               want    string
        }{
-               {0, 0, "+Inf"},
-               {100, 0, "+Inf"},
-               {-1, 0, "-Inf"},
-               {0, 10, "+Inf"},
-               {100, 20, "+Inf"},
-               {-1, 30, "-Inf"},
+               {false, 0, "+Inf"},
+               {true, 0, "-Inf"},
+               {false, 10, "+Inf"},
+               {true, 30, "-Inf"},
        } {
-               x := f.SetPrec(test.prec).SetInf(test.sign)
+               x := f.SetPrec(test.prec).SetInf(test.signbit)
                if got := x.String(); got != test.want || x.Prec() != test.prec {
-                       t.Errorf("SetInf(%d) = %s (prec = %d); want %s (prec = %d)", test.sign, got, x.Prec(), test.want, test.prec)
+                       t.Errorf("SetInf(%v) = %s (prec = %d); want %s (prec = %d)", test.signbit, got, x.Prec(), test.want, test.prec)
                }
        }
 }
@@ -786,7 +770,6 @@ func TestFloatUint64(t *testing.T) {
                {"18446744073709551616", math.MaxUint64, Below},
                {"1e10000", math.MaxUint64, Below},
                {"+Inf", math.MaxUint64, Below},
-               {"NaN", 0, Undef},
        } {
                x := makeFloat(test.x)
                out, acc := x.Uint64()
@@ -827,7 +810,6 @@ func TestFloatInt64(t *testing.T) {
                {"9223372036854775808", math.MaxInt64, Below},
                {"1e10000", math.MaxInt64, Below},
                {"+Inf", math.MaxInt64, Below},
-               {"NaN", 0, Undef},
        } {
                x := makeFloat(test.x)
                out, acc := x.Int64()
@@ -891,12 +873,6 @@ func TestFloatFloat32(t *testing.T) {
                        t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
                }
        }
-
-       // test NaN
-       x := makeFloat("NaN")
-       if out, acc := x.Float32(); out == out || acc != Undef {
-               t.Errorf("NaN: got %g (%s); want NaN (Undef)", out, acc)
-       }
 }
 
 func TestFloatFloat64(t *testing.T) {
@@ -963,12 +939,6 @@ func TestFloatFloat64(t *testing.T) {
                        t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
                }
        }
-
-       // test NaN
-       x := makeFloat("NaN")
-       if out, acc := x.Float64(); out == out || acc != Undef {
-               t.Errorf("NaN: got %g (%s); want NaN (Undef)", out, acc)
-       }
 }
 
 func TestFloatInt(t *testing.T) {
@@ -983,7 +953,6 @@ func TestFloatInt(t *testing.T) {
                {"Inf", "nil", Below},
                {"+Inf", "nil", Below},
                {"-Inf", "nil", Above},
-               {"NaN", "nil", Undef},
                {"1", "1", Exact},
                {"-1", "-1", Exact},
                {"1.23", "1", Below},
@@ -1028,7 +997,6 @@ func TestFloatRat(t *testing.T) {
                {"Inf", "nil", Below},
                {"+Inf", "nil", Below},
                {"-Inf", "nil", Above},
-               {"NaN", "nil", Undef},
                {"1", "1/1", Exact},
                {"-1", "-1/1", Exact},
                {"1.25", "5/4", Exact},
@@ -1056,7 +1024,7 @@ func TestFloatRat(t *testing.T) {
                // inverse conversion
                if res != nil {
                        got := new(Float).SetPrec(64).SetRat(res)
-                       if got.Cmp(x).Neq() {
+                       if got.Cmp(x) != 0 {
                                t.Errorf("%s: got %s; want %s", test.x, got, x)
                        }
                }
@@ -1081,17 +1049,16 @@ func TestFloatAbs(t *testing.T) {
                "1e-1000",
                "1e1000",
                "Inf",
-               "NaN",
        } {
                p := makeFloat(test)
                a := new(Float).Abs(p)
-               if !feq(a, p) {
+               if !alike(a, p) {
                        t.Errorf("%s: got %s; want %s", test, a.Format('g', 10), test)
                }
 
                n := makeFloat("-" + test)
                a.Abs(n)
-               if !feq(a, p) {
+               if !alike(a, p) {
                        t.Errorf("-%s: got %s; want %s", test, a.Format('g', 10), test)
                }
        }
@@ -1106,16 +1073,15 @@ func TestFloatNeg(t *testing.T) {
                "1e-1000",
                "1e1000",
                "Inf",
-               "NaN",
        } {
                p1 := makeFloat(test)
                n1 := makeFloat("-" + test)
                n2 := new(Float).Neg(p1)
                p2 := new(Float).Neg(n2)
-               if !feq(n2, n1) {
+               if !alike(n2, n1) {
                        t.Errorf("%s: got %s; want %s", test, n2.Format('g', 10), n1.Format('g', 10))
                }
-               if !feq(p2, p1) {
+               if !alike(p2, p1) {
                        t.Errorf("%s: got %s; want %s", test, p2.Format('g', 10), p1.Format('g', 10))
                }
        }
@@ -1133,7 +1099,7 @@ func TestFloatInc(t *testing.T) {
                for i := 0; i < n; i++ {
                        x.Add(&x, &one)
                }
-               if x.Cmp(new(Float).SetInt64(n)).Neq() {
+               if x.Cmp(new(Float).SetInt64(n)) != 0 {
                        t.Errorf("prec = %d: got %s; want %d", prec, &x, n)
                }
        }
@@ -1174,14 +1140,14 @@ func TestFloatAdd(t *testing.T) {
                                        got := new(Float).SetPrec(prec).SetMode(mode)
                                        got.Add(x, y)
                                        want := zbits.round(prec, mode)
-                                       if got.Cmp(want).Neq() {
+                                       if got.Cmp(want) != 0 {
                                                t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t+    %s %v\n\t=    %s\n\twant %s",
                                                        i, prec, mode, x, xbits, y, ybits, got, want)
                                        }
 
                                        got.Sub(z, x)
                                        want = ybits.round(prec, mode)
-                                       if got.Cmp(want).Neq() {
+                                       if got.Cmp(want) != 0 {
                                                t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t-    %s %v\n\t=    %s\n\twant %s",
                                                        i, prec, mode, z, zbits, x, xbits, got, want)
                                        }
@@ -1276,17 +1242,17 @@ func TestFloatMul(t *testing.T) {
                                        got := new(Float).SetPrec(prec).SetMode(mode)
                                        got.Mul(x, y)
                                        want := zbits.round(prec, mode)
-                                       if got.Cmp(want).Neq() {
+                                       if got.Cmp(want) != 0 {
                                                t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t*    %s %v\n\t=    %s\n\twant %s",
                                                        i, prec, mode, x, xbits, y, ybits, got, want)
                                        }
 
-                                       if x.IsZero() {
+                                       if x.Sign() == 0 {
                                                continue // ignore div-0 case (not invertable)
                                        }
                                        got.Quo(z, x)
                                        want = ybits.round(prec, mode)
-                                       if got.Cmp(want).Neq() {
+                                       if got.Cmp(want) != 0 {
                                                t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t/    %s %v\n\t=    %s\n\twant %s",
                                                        i, prec, mode, z, zbits, x, xbits, got, want)
                                        }
@@ -1369,7 +1335,7 @@ func TestIssue6866(t *testing.T) {
                p.Mul(p, psix)
                z2.Sub(two, p)
 
-               if z1.Cmp(z2).Neq() {
+               if z1.Cmp(z2) != 0 {
                        t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2)
                }
                if z1.Sign() != 0 {
@@ -1420,7 +1386,7 @@ func TestFloatQuo(t *testing.T) {
                                prec := uint(preci + d)
                                got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y)
                                want := bits.round(prec, mode)
-                               if got.Cmp(want).Neq() {
+                               if got.Cmp(want) != 0 {
                                        t.Errorf("i = %d, prec = %d, %s:\n\t     %s\n\t/    %s\n\t=    %s\n\twant %s",
                                                i, prec, mode, x, y, got, want)
                                }
@@ -1472,10 +1438,10 @@ func TestFloatQuoSmoke(t *testing.T) {
 
 // TestFloatArithmeticSpecialValues tests that Float operations produce the
 // correct results for combinations of zero (±0), finite (±1 and ±2.71828),
-// and non-finite (±Inf, NaN) operands.
+// and non-finite (±Inf) operands.
 func TestFloatArithmeticSpecialValues(t *testing.T) {
        zero := 0.0
-       args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1), math.NaN()}
+       args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
        xx := new(Float)
        yy := new(Float)
        got := new(Float)
@@ -1486,10 +1452,15 @@ func TestFloatArithmeticSpecialValues(t *testing.T) {
                        // check conversion is correct
                        // (no need to do this for y, since we see exactly the
                        // same values there)
-                       if got, acc := xx.Float64(); !math.IsNaN(x) && (got != x || acc != Exact) {
+                       if got, acc := xx.Float64(); got != x || acc != Exact {
                                t.Errorf("Float(%g) == %g (%s)", x, got, acc)
                        }
                        for _, y := range args {
+                               // At the moment an Inf operand always leads to a panic (known bug).
+                               // TODO(gri) remove this once the bug is fixed.
+                               if math.IsInf(x, 0) || math.IsInf(y, 0) {
+                                       continue
+                               }
                                yy.SetFloat64(y)
                                var op string
                                var z float64
@@ -1507,20 +1478,18 @@ func TestFloatArithmeticSpecialValues(t *testing.T) {
                                        z = x * y
                                        got.Mul(xx, yy)
                                case 3:
+                                       if x == 0 && y == 0 {
+                                               // TODO(gri) check for ErrNaN
+                                               continue // 0/0 panics with ErrNaN
+                                       }
                                        op = "/"
                                        z = x / y
                                        got.Quo(xx, yy)
                                default:
                                        panic("unreachable")
                                }
-                               // At the moment an Inf operand always leads to a NaN result (known bug).
-                               // TODO(gri) remove this once the bug is fixed.
-                               if math.IsInf(x, 0) || math.IsInf(y, 0) {
-                                       want.SetNaN()
-                               } else {
-                                       want.SetFloat64(z)
-                               }
-                               if !feq(got, want) {
+                               want.SetFloat64(z)
+                               if !alike(got, want) {
                                        t.Errorf("%5g %s %5g = %5s; want %5s", x, op, y, got, want)
                                }
                        }
@@ -1645,11 +1614,11 @@ func TestFloatArithmeticRounding(t *testing.T) {
 }
 
 // TestFloatCmpSpecialValues tests that Cmp produces the correct results for
-// combinations of zero (±0), finite (±1 and ±2.71828), and non-finite (±Inf,
-// NaN) operands.
+// combinations of zero (±0), finite (±1 and ±2.71828), and non-finite (±Inf)
+// operands.
 func TestFloatCmpSpecialValues(t *testing.T) {
        zero := 0.0
-       args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1), math.NaN()}
+       args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
        xx := new(Float)
        yy := new(Float)
        for i := 0; i < 4; i++ {
@@ -1658,20 +1627,18 @@ func TestFloatCmpSpecialValues(t *testing.T) {
                        // check conversion is correct
                        // (no need to do this for y, since we see exactly the
                        // same values there)
-                       if got, acc := xx.Float64(); !math.IsNaN(x) && (got != x || acc != Exact) {
+                       if got, acc := xx.Float64(); got != x || acc != Exact {
                                t.Errorf("Float(%g) == %g (%s)", x, got, acc)
                        }
                        for _, y := range args {
                                yy.SetFloat64(y)
-                               got := xx.Cmp(yy).Acc()
-                               want := Undef
+                               got := xx.Cmp(yy)
+                               want := 0
                                switch {
                                case x < y:
-                                       want = Below
-                               case x == y:
-                                       want = Exact
+                                       want = -1
                                case x > y:
-                                       want = Above
+                                       want = +1
                                }
                                if got != want {
                                        t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want)
index 8905718d2981578727c90f2de0b6e3f341e9ed4f..7dc9a2800c08f34b8009ef71eba1091c46887d36 100644 (file)
@@ -73,10 +73,8 @@ func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
                prec = 64
        }
 
-       // NaNs ignore sign, mantissa, and exponent so we can set
-       // them below while having a valid value for z in case of
-       // errors.
-       z.SetNaN()
+       // A reasonable value in case of an error.
+       z.form = zero
 
        // sign
        z.neg, err = scanSign(r)
@@ -260,11 +258,6 @@ func (x *Float) Append(buf []byte, format byte, prec int) []byte {
                return append(buf, "Inf"...)
        }
 
-       // NaN
-       if x.IsNaN() {
-               return append(buf, "NaN"...)
-       }
-
        // easy formats
        switch format {
        case 'b':
index 17c8b147862506522fa28d13f31639fe3b11ef56..e7920d0c079882a196c5eb80349e80f1ffb4ce3f 100644 (file)
@@ -102,7 +102,7 @@ func TestFloatSetFloat64String(t *testing.T) {
                }
                f, _ := x.Float64()
                want := new(Float).SetFloat64(test.x)
-               if x.Cmp(want).Neq() {
+               if x.Cmp(want) != 0 {
                        t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
                }
        }
index 5e4a9cbe89ceb455bc2436a6b5362609455c6488..7db10238bc64603004f5bc8c107cd4a7921bff8a 100644 (file)
@@ -50,88 +50,62 @@ func Example_Shift() {
 func ExampleFloat_Cmp() {
        inf := math.Inf(1)
        zero := 0.0
-       nan := math.NaN()
 
-       operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf, nan}
+       operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf}
 
-       fmt.Println("   x     y   cmp   eql  neq  lss  leq  gtr  geq")
-       fmt.Println("-----------------------------------------------")
+       fmt.Println("   x     y  cmp")
+       fmt.Println("---------------")
        for _, x64 := range operands {
                x := big.NewFloat(x64)
                for _, y64 := range operands {
                        y := big.NewFloat(y64)
-                       t := x.Cmp(y)
-                       fmt.Printf(
-                               "%4s  %4s  %5s   %c    %c    %c    %c    %c    %c\n",
-                               x, y, t.Acc(),
-                               mark(t.Eql()), mark(t.Neq()), mark(t.Lss()), mark(t.Leq()), mark(t.Gtr()), mark(t.Geq()))
+                       fmt.Printf("%4s  %4s  %3d\n", x, y, x.Cmp(y))
                }
                fmt.Println()
        }
 
        // Output:
-       //    x     y   cmp   eql  neq  lss  leq  gtr  geq
-       // -----------------------------------------------
-       // -Inf  -Inf  Exact   ●    ○    ○    ●    ○    ●
-       // -Inf  -1.2  Below   ○    ●    ●    ●    ○    ○
-       // -Inf    -0  Below   ○    ●    ●    ●    ○    ○
-       // -Inf     0  Below   ○    ●    ●    ●    ○    ○
-       // -Inf   1.2  Below   ○    ●    ●    ●    ○    ○
-       // -Inf  +Inf  Below   ○    ●    ●    ●    ○    ○
-       // -Inf   NaN  Undef   ○    ●    ○    ○    ○    ○
+       //    x     y  cmp
+       // ---------------
+       // -Inf  -Inf    0
+       // -Inf  -1.2   -1
+       // -Inf    -0   -1
+       // -Inf     0   -1
+       // -Inf   1.2   -1
+       // -Inf  +Inf   -1
        //
-       // -1.2  -Inf  Above   ○    ●    ○    ○    ●    ●
-       // -1.2  -1.2  Exact   ●    ○    ○    ●    ○    ●
-       // -1.2    -0  Below   ○    ●    ●    ●    ○    ○
-       // -1.2     0  Below   ○    ●    ●    ●    ○    ○
-       // -1.2   1.2  Below   ○    ●    ●    ●    ○    ○
-       // -1.2  +Inf  Below   ○    ●    ●    ●    ○    ○
-       // -1.2   NaN  Undef   ○    ●    ○    ○    ○    ○
+       // -1.2  -Inf    1
+       // -1.2  -1.2    0
+       // -1.2    -0   -1
+       // -1.2     0   -1
+       // -1.2   1.2   -1
+       // -1.2  +Inf   -1
        //
-       //   -0  -Inf  Above   ○    ●    ○    ○    ●    ●
-       //   -0  -1.2  Above   ○    ●    ○    ○    ●    ●
-       //   -0    -0  Exact   ●    ○    ○    ●    ○    ●
-       //   -0     0  Exact   ●    ○    ○    ●    ○    ●
-       //   -0   1.2  Below   ○    ●    ●    ●    ○    ○
-       //   -0  +Inf  Below   ○    ●    ●    ●    ○    ○
-       //   -0   NaN  Undef   ○    ●    ○    ○    ○    ○
+       //   -0  -Inf    1
+       //   -0  -1.2    1
+       //   -0    -0    0
+       //   -0     0    0
+       //   -0   1.2   -1
+       //   -0  +Inf   -1
        //
-       //    0  -Inf  Above   ○    ●    ○    ○    ●    ●
-       //    0  -1.2  Above   ○    ●    ○    ○    ●    ●
-       //    0    -0  Exact   ●    ○    ○    ●    ○    ●
-       //    0     0  Exact   ●    ○    ○    ●    ○    ●
-       //    0   1.2  Below   ○    ●    ●    ●    ○    ○
-       //    0  +Inf  Below   ○    ●    ●    ●    ○    ○
-       //    0   NaN  Undef   ○    ●    ○    ○    ○    ○
+       //    0  -Inf    1
+       //    0  -1.2    1
+       //    0    -0    0
+       //    0     0    0
+       //    0   1.2   -1
+       //    0  +Inf   -1
        //
-       //  1.2  -Inf  Above   ○    ●    ○    ○    ●    ●
-       //  1.2  -1.2  Above   ○    ●    ○    ○    ●    ●
-       //  1.2    -0  Above   ○    ●    ○    ○    ●    ●
-       //  1.2     0  Above   ○    ●    ○    ○    ●    ●
-       //  1.2   1.2  Exact   ●    ○    ○    ●    ○    ●
-       //  1.2  +Inf  Below   ○    ●    ●    ●    ○    ○
-       //  1.2   NaN  Undef   ○    ●    ○    ○    ○    ○
+       //  1.2  -Inf    1
+       //  1.2  -1.2    1
+       //  1.2    -0    1
+       //  1.2     0    1
+       //  1.2   1.2    0
+       //  1.2  +Inf   -1
        //
-       // +Inf  -Inf  Above   ○    ●    ○    ○    ●    ●
-       // +Inf  -1.2  Above   ○    ●    ○    ○    ●    ●
-       // +Inf    -0  Above   ○    ●    ○    ○    ●    ●
-       // +Inf     0  Above   ○    ●    ○    ○    ●    ●
-       // +Inf   1.2  Above   ○    ●    ○    ○    ●    ●
-       // +Inf  +Inf  Exact   ●    ○    ○    ●    ○    ●
-       // +Inf   NaN  Undef   ○    ●    ○    ○    ○    ○
-       //
-       //  NaN  -Inf  Undef   ○    ●    ○    ○    ○    ○
-       //  NaN  -1.2  Undef   ○    ●    ○    ○    ○    ○
-       //  NaN    -0  Undef   ○    ●    ○    ○    ○    ○
-       //  NaN     0  Undef   ○    ●    ○    ○    ○    ○
-       //  NaN   1.2  Undef   ○    ●    ○    ○    ○    ○
-       //  NaN  +Inf  Undef   ○    ●    ○    ○    ○    ○
-       //  NaN   NaN  Undef   ○    ●    ○    ○    ○    ○
-}
-
-func mark(p bool) rune {
-       if p {
-               return '●'
-       }
-       return '○'
+       // +Inf  -Inf    1
+       // +Inf  -1.2    1
+       // +Inf    -0    1
+       // +Inf     0    1
+       // +Inf   1.2    1
+       // +Inf  +Inf    0
 }
index 5502eda69b515e10687542bb7d0ef26a6629f590..0a9edfd7b22330586dc29290f9609ca1a040c36d 100644 (file)
@@ -19,7 +19,7 @@ import "strconv"
 
 // bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
 func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
-       if debugFloat && !f.IsFinite() {
+       if debugFloat && f.IsInf() {
                panic("non-finite float")
        }