math/big: wrap Float.Cmp result in struct to prevent wrong use

Float.Cmp used to return a value < 0, 0, or > 0 depending on how
arguments x, y compared against each other. With the possibility
of NaNs, the result was changed into an Accuracy (to include Undef).
Consequently, Float.Cmp results could still be compared for (in-)
equality with 0, but comparing if < 0 or > 0 would provide the
wrong answer w/o any obvious notice by the compiler.

This change wraps Float.Cmp results into a struct and accessors
are used to access the desired result. This prevents incorrect
use.

Change-Id: I34e6a6c1859251ec99b5cf953e82542025ace56f
Reviewed-on: https://go-review.googlesource.com/7526
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Robert Griesemer 2015-03-13 17:24:30 -07:00
parent b100216441
commit 23fd374bf2
4 changed files with 30 additions and 25 deletions

View file

@ -1446,6 +1446,10 @@ 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
@ -1453,44 +1457,45 @@ func (z *Float) Quo(x, y *Float) *Float {
// Above if x > y
// Undef if any of x, y is NaN
//
func (x *Float) Cmp(y *Float) Accuracy {
func (x *Float) Cmp(y *Float) cmpResult {
if debugFloat {
x.validate()
y.validate()
}
if x.form == nan || y.form == nan {
return Undef
return cmpResult{Undef}
}
mx := x.ord()
my := y.ord()
switch {
case mx < my:
return Below
return cmpResult{Below}
case mx > my:
return Above
return cmpResult{Above}
}
// mx == my
// only if |mx| == 1 we have to compare the mantissae
switch mx {
case -1:
return y.ucmp(x)
return cmpResult{y.ucmp(x)}
case +1:
return x.ucmp(y)
return cmpResult{x.ucmp(y)}
}
return Exact
return cmpResult{Exact}
}
// The following accessors simplify testing of Cmp results.
func (acc Accuracy) Eql() bool { return acc == Exact }
func (acc Accuracy) Neq() bool { return acc != Exact }
func (acc Accuracy) Lss() bool { return acc == Below }
func (acc Accuracy) Leq() bool { return acc&Above == 0 }
func (acc Accuracy) Gtr() bool { return acc == Above }
func (acc Accuracy) Geq() bool { return acc&Below == 0 }
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:
//