Skip to content

proposal: math: add an IsAlmostEqual function #17675

@johnrs

Description

@johnrs

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
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions