53 lines
1.4 KiB
Go
53 lines
1.4 KiB
Go
package helper
|
|
|
|
import (
|
|
"math"
|
|
)
|
|
|
|
// EqFloat64Fuzzy returns true if two floats aren't meaningfully distinct from each other.
|
|
//
|
|
// NaNs aren't considered distinct (meaning this function will return true if both inputs are NaN).
|
|
func EqFloat64Fuzzy(a, b float64) bool {
|
|
// if either input is NaN...
|
|
if math.IsNaN(a) || math.IsNaN(b) {
|
|
// return true if they'be both NaN (think SQL's "IS NOT DISTINCT FROM")
|
|
// otherwise was was NaN and the other was not, so return false.
|
|
return math.IsNaN(a) == math.IsNaN(b)
|
|
}
|
|
|
|
// if either input is infinity...
|
|
if math.IsInf(a, 0) || math.IsInf(b, 0) {
|
|
// return true if they're the same value (both +infinity or both -infinity)
|
|
// false otherwise (infinity vs a finite number, or an infinity with the opposite sign)
|
|
return a == b
|
|
}
|
|
|
|
const epsilon = 1e-9
|
|
|
|
absA, absB, absDiff := math.Abs(a), math.Abs(b), math.Abs(a-b)
|
|
|
|
// For numbers close to zero, use absolute epsilon
|
|
if min(absA, absB, absDiff) < math.SmallestNonzeroFloat64 {
|
|
return absDiff < epsilon
|
|
}
|
|
|
|
return absDiff < epsilon*max(absA, absB)
|
|
}
|
|
|
|
// EqFloat64SliceFuzzy returns true if two lists of floats aren't meaningfully distinct from each other.
|
|
//
|
|
// Returns false if the lists are of different lengths, [EqFloat64Fuzzy] returns false for any pair of floats.
|
|
func EqFloat64SliceFuzzy(a, b []float64) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
|
|
for i := range a {
|
|
if !EqFloat64Fuzzy(a[i], b[i]) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|