-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Closed
Labels
Description
Proposal
Add an IsAlmostEqual function to the math package.
Justification
Although equating floating-point numbers is generally a bad idea,
sometimes it is necessary. For example, an iterative square root
algorithm might need an equate to determine when to quit.
Possible Solution
Add something like this function to the math package.
// IsAlmostEqual returns the near equality of 2 float64's based on
// a variable sized window, "nrSteps" big.
// A step's size is the amount by which adjacent numbers differ.
// The step size is based on the larger of the two numbers being compared.
//
// 0 steps requires an exact (generally not what you want) match.
// 1 or 2 steps is a common setting for simple calculations.
// Complicated calculations with many accumulated errors might require more steps.
//
// Special cases are handled as follows (regardless of parameter order):
// +Inf, +Inf ==> true
// -Inf, -Inf ==> true
// +Inf, x ==> false (x != +Inf)
// -Inf, x ==> false (x != -Inf)
// NaN, x ==> false
//
func IsAlmostEqual(a, b float64, nrSteps int) (equal bool) {
if nrSteps < 0 {
return false
}
// This allows matching infinities to pass.
if a == b {
return true
}
max := math.Max(math.Abs(a), math.Abs(b))
stepSize := math.Nextafter(max, math.Inf(+1)) - max // max of either +Inf or NaN ==> NaN
return math.Abs(a-b) <= float64(nrSteps)*stepSize // NaN fails
}