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 }