]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc/big: updated vendored version of math/big (fix build)
authorRobert Griesemer <gri@golang.org>
Thu, 2 Apr 2015 21:47:03 +0000 (14:47 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 2 Apr 2015 22:05:22 +0000 (22:05 +0000)
Change-Id: I04c2bd18a47cc775c78d074fe521cef2b0d6e7f0
Reviewed-on: https://go-review.googlesource.com/8426
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/internal/gc/big/accuracy_string.go
src/cmd/internal/gc/big/float.go
src/cmd/internal/gc/big/float_test.go
src/cmd/internal/gc/big/floatconv.go
src/cmd/internal/gc/big/floatconv_test.go
src/cmd/internal/gc/big/floatexample_test.go
src/cmd/internal/gc/big/ftoa.go
src/cmd/internal/gc/big/int.go
src/cmd/internal/gc/big/int_test.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..ed55e8e5135da469f74f25129abeb106fd82bfec 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:
@@ -1442,8 +1400,9 @@ func (x *Float) ucmp(y *Float) Accuracy {
 // it is changed to the larger of x's or y's precision before the operation.
 // 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.
+// result. Add panics with ErrNaN if x and y are infinities with opposite
+// signs. The value of z is undefined in that case.
+//
 // 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 {
@@ -1455,46 +1414,59 @@ func (z *Float) Add(x, y *Float) *Float {
                z.prec = umax32(x.prec, y.prec)
        }
 
-       // special cases
-       if x.form != finite || y.form != finite {
-               if x.form > finite || y.form > finite {
-                       // TODO(gri) handle Inf separately
-                       return z.SetNaN()
-               }
-               if x.form == zero {
-                       z.Set(y)
-                       if z.form == zero {
-                               z.neg = x.neg && y.neg // -0 + -0 == -0
+       if x.form == finite && y.form == finite {
+               // x + y (commom case)
+               z.neg = x.neg
+               if x.neg == y.neg {
+                       // x + y == x + y
+                       // (-x) + (-y) == -(x + y)
+                       z.uadd(x, y)
+               } else {
+                       // x + (-y) == x - y == -(y - x)
+                       // (-x) + y == y - x == -(x - y)
+                       if x.ucmp(y) > 0 {
+                               z.usub(x, y)
+                       } else {
+                               z.neg = !z.neg
+                               z.usub(y, x)
                        }
-                       return z
                }
-               // y == ±0
-               return z.Set(x)
+               return z
        }
 
-       // x, y != 0
-       z.neg = x.neg
-       if x.neg == y.neg {
-               // x + y == x + y
-               // (-x) + (-y) == -(x + y)
-               z.uadd(x, y)
-       } else {
-               // x + (-y) == x - y == -(y - x)
-               // (-x) + y == y - x == -(x - y)
-               if x.ucmp(y) == Above {
-                       z.usub(x, y)
-               } else {
-                       z.neg = !z.neg
-                       z.usub(y, x)
-               }
+       if x.form == inf && y.form == inf && x.neg != y.neg {
+               // +Inf + -Inf
+               // -Inf + +Inf
+               // value of z is undefined but make sure it's valid
+               z.acc = Exact
+               z.form = zero
+               z.neg = false
+               panic(ErrNaN{"addition of infinities with opposite signs"})
        }
 
-       return z
+       if x.form == zero && y.form == zero {
+               // ±0 + ±0
+               z.acc = Exact
+               z.form = zero
+               z.neg = x.neg && y.neg // -0 + -0 == -0
+               return z
+       }
+
+       if x.form == inf || y.form == zero {
+               // ±Inf + y
+               // x + ±0
+               return z.Set(x)
+       }
+
+       // ±0 + y
+       // x + ±Inf
+       return z.Set(y)
 }
 
 // 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.
+// Sub panics with ErrNaN if x and y are infinities with equal
+// signs. The value of z is undefined in that case.
 func (z *Float) Sub(x, y *Float) *Float {
        if debugFloat {
                x.validate()
@@ -1505,46 +1477,59 @@ func (z *Float) Sub(x, y *Float) *Float {
                z.prec = umax32(x.prec, y.prec)
        }
 
-       // special cases
-       if x.form != finite || y.form != finite {
-               if x.form > finite || y.form > finite {
-                       // TODO(gri) handle Inf separately
-                       return z.SetNaN()
-               }
-               if x.form == zero {
-                       z.Neg(y)
-                       if z.form == zero {
-                               z.neg = x.neg && !y.neg // -0 - 0 == -0
+       if x.form == finite && y.form == finite {
+               // x - y (common case)
+               z.neg = x.neg
+               if x.neg != y.neg {
+                       // x - (-y) == x + y
+                       // (-x) - y == -(x + y)
+                       z.uadd(x, y)
+               } else {
+                       // x - y == x - y == -(y - x)
+                       // (-x) - (-y) == y - x == -(x - y)
+                       if x.ucmp(y) > 0 {
+                               z.usub(x, y)
+                       } else {
+                               z.neg = !z.neg
+                               z.usub(y, x)
                        }
-                       return z
                }
-               // y == ±0
-               return z.Set(x)
+               return z
        }
 
-       // x, y != 0
-       z.neg = x.neg
-       if x.neg != y.neg {
-               // x - (-y) == x + y
-               // (-x) - y == -(x + y)
-               z.uadd(x, y)
-       } else {
-               // x - y == x - y == -(y - x)
-               // (-x) - (-y) == y - x == -(x - y)
-               if x.ucmp(y) == Above {
-                       z.usub(x, y)
-               } else {
-                       z.neg = !z.neg
-                       z.usub(y, x)
-               }
+       if x.form == inf && y.form == inf && x.neg == y.neg {
+               // +Inf - +Inf
+               // -Inf - -Inf
+               // value of z is undefined but make sure it's valid
+               z.acc = Exact
+               z.form = zero
+               z.neg = false
+               panic(ErrNaN{"subtraction of infinities with equal signs"})
        }
 
-       return z
+       if x.form == zero && y.form == zero {
+               // ±0 - ±0
+               z.acc = Exact
+               z.form = zero
+               z.neg = x.neg && !y.neg // -0 - +0 == -0
+               return z
+       }
+
+       if x.form == inf || y.form == zero {
+               // ±Inf - y
+               // x - ±0
+               return z.Set(x)
+       }
+
+       // ±0 - y
+       // x - ±Inf
+       return z.Neg(y)
 }
 
 // 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.
+// Mul panics with ErrNaN if one operand is zero and the other
+// operand an infinity. The value of z is undefined in that case.
 func (z *Float) Mul(x, y *Float) *Float {
        if debugFloat {
                x.validate()
@@ -1557,27 +1542,39 @@ func (z *Float) Mul(x, y *Float) *Float {
 
        z.neg = x.neg != y.neg
 
-       // special cases
-       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.form = zero
+       if x.form == finite && y.form == finite {
+               // x * y (common case)
+               z.umul(x, y)
                return z
        }
 
-       // x, y != 0
-       z.umul(x, y)
+       z.acc = Exact
+       if x.form == zero && y.form == inf || x.form == inf && y.form == zero {
+               // ±0 * ±Inf
+               // ±Inf * ±0
+               // value of z is undefined but make sure it's valid
+               z.form = zero
+               z.neg = false
+               panic(ErrNaN{"multiplication of zero with infinity"})
+       }
 
+       if x.form == inf || y.form == inf {
+               // ±Inf * y
+               // x * ±Inf
+               z.form = inf
+               return z
+       }
+
+       // ±0 * y
+       // x * ±0
+       z.form = zero
        return z
 }
 
 // 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 with ErrNaN if both operands are zero or infinities.
+// The value of z is undefined in that case.
 func (z *Float) Quo(x, y *Float) *Float {
        if debugFloat {
                x.validate()
@@ -1590,83 +1587,68 @@ func (z *Float) Quo(x, y *Float) *Float {
 
        z.neg = x.neg != y.neg
 
-       // special cases
-       z.acc = Exact
-       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
-               if x.form == zero {
-                       if y.form == zero {
-                               return z.SetNaN()
-                       }
-                       z.form = zero
-                       return z
-               }
-               // y == ±0
-               z.form = inf
+       if x.form == finite && y.form == finite {
+               // x / y (common case)
+               z.uquo(x, y)
                return z
        }
 
-       // x, y != 0
-       z.uquo(x, y)
+       z.acc = Exact
+       if x.form == zero && y.form == zero || x.form == inf && y.form == inf {
+               // ±0 / ±0
+               // ±Inf / ±Inf
+               // value of z is undefined but make sure it's valid
+               z.form = zero
+               z.neg = false
+               panic(ErrNaN{"division of zero by zero or infinity by infinity"})
+       }
 
-       return z
-}
+       if x.form == zero || y.form == inf {
+               // ±0 / y
+               // x / ±Inf
+               z.form = zero
+               return z
+       }
 
-type cmpResult struct {
-       acc Accuracy
+       // x / ±0
+       // ±Inf / y
+       z.form = inf
+       return z
 }
 
 // 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 +1657,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 +1666,6 @@ func (x *Float) ord() int {
                return 0
        case inf:
                m = 2
-       default:
-               panic("unreachable")
        }
        if x.neg {
                m = -m
index 9d101531de871352062570e187ed5138b9312849..2a48ec44651477558d01cd92d1cc1d0b6ee8821b 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 infinite (±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,41 +1452,59 @@ 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 {
                                yy.SetFloat64(y)
-                               var op string
-                               var z float64
+                               var (
+                                       op string
+                                       z  float64
+                                       f  func(z, x, y *Float) *Float
+                               )
                                switch i {
                                case 0:
                                        op = "+"
                                        z = x + y
-                                       got.Add(xx, yy)
+                                       f = (*Float).Add
                                case 1:
                                        op = "-"
                                        z = x - y
-                                       got.Sub(xx, yy)
+                                       f = (*Float).Sub
                                case 2:
                                        op = "*"
                                        z = x * y
-                                       got.Mul(xx, yy)
+                                       f = (*Float).Mul
                                case 3:
                                        op = "/"
                                        z = x / y
-                                       got.Quo(xx, yy)
+                                       f = (*Float).Quo
                                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)
+                               var errnan bool // set if execution of f panicked with ErrNaN
+                               // protect execution of f
+                               func() {
+                                       defer func() {
+                                               if p := recover(); p != nil {
+                                                       _ = p.(ErrNaN) // re-panic if not ErrNaN
+                                                       errnan = true
+                                               }
+                                       }()
+                                       f(got, xx, yy)
+                               }()
+                               if math.IsNaN(z) {
+                                       if !errnan {
+                                               t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got)
+                                       }
+                                       continue
+                               }
+                               if errnan {
+                                       t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want)
+                                       continue
                                }
-                               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 +1629,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 infinite (±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 +1642,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")
        }
 
index 0695d78973728dcf8d66dfff85c667de4765108c..3410ec47295864a1ffe60b5601fed6b72c2a1d65 100644 (file)
@@ -184,6 +184,10 @@ func (z *Int) MulRange(a, b int64) *Int {
 
 // Binomial sets z to the binomial coefficient of (n, k) and returns z.
 func (z *Int) Binomial(n, k int64) *Int {
+       // reduce the number of multiplications by reducing k
+       if n/2 < k && k <= n {
+               k = n - k // Binomial(n, k) == Binomial(n, n-k)
+       }
        var a, b Int
        a.MulRange(n-k+1, n)
        b.MulRange(1, k)
index dff8057cf9f5eb1fc6f22cd03f6cd736226e70a1..a972a7249bbec4024688f31a1cd2aeb73802e6bf 100644 (file)
@@ -219,6 +219,45 @@ func TestMulRangeZ(t *testing.T) {
        }
 }
 
+func TestBinomial(t *testing.T) {
+       var z Int
+       for _, test := range []struct {
+               n, k int64
+               want string
+       }{
+               {0, 0, "1"},
+               {0, 1, "0"},
+               {1, 0, "1"},
+               {1, 1, "1"},
+               {1, 10, "0"},
+               {4, 0, "1"},
+               {4, 1, "4"},
+               {4, 2, "6"},
+               {4, 3, "4"},
+               {4, 4, "1"},
+               {10, 1, "10"},
+               {10, 9, "10"},
+               {10, 5, "252"},
+               {11, 5, "462"},
+               {11, 6, "462"},
+               {100, 10, "17310309456440"},
+               {100, 90, "17310309456440"},
+               {1000, 10, "263409560461970212832400"},
+               {1000, 990, "263409560461970212832400"},
+       } {
+               if got := z.Binomial(test.n, test.k).String(); got != test.want {
+                       t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want)
+               }
+       }
+}
+
+func BenchmarkBinomial(b *testing.B) {
+       var z Int
+       for i := b.N - 1; i >= 0; i-- {
+               z.Binomial(1000, 990)
+       }
+}
+
 // Examples from the Go Language Spec, section "Arithmetic operators"
 var divisionSignsTests = []struct {
        x, y int64
@@ -353,7 +392,7 @@ func checkBytes(b []byte) bool {
 }
 
 func TestBytes(t *testing.T) {
-       if err := quick.Check(checkSetBytes, nil); err != nil {
+       if err := quick.Check(checkBytes, nil); err != nil {
                t.Error(err)
        }
 }