github.com/matrixorigin/matrixone@v1.2.0/pkg/common/assertx/float64.go (about) 1 // Copyright 2023 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package assertx 16 17 import ( 18 "math" 19 ) 20 21 // Float64 values have minor numerical differences between Apple M2 and Linux EC2, 22 // so we use an epsilon value to compare them in UT. We could not use reflect.DeepEqual because 23 // of these minor differences. We cannot use assert.InEpsilon because it requires the first 24 // argument to be non-zero. 25 // 26 // The epsilon 1e-9 epsilon is based on the following observation: 27 // - `strconv.FormatFloat(float64(value), 'f', -1, 64)` we use for outputting float64 values. 28 // - precision difference between Apple M2 and Linux EC2 float64 results (approx 1e-13) 29 // - service_weaver: https://github.com/ServiceWeaver/weaver/blob/8e7c225542b8f8267ec0da3e01a098366b6f8daf/internal/weaver/load.go#L31 30 // - google lib: https://github.com/google/differential-privacy/blob/91b4ecebf33e71b8a215b7ea8325fb5e47b12671/privacy-on-beam/pbeam/pbeamtest/pbeamtest_test.go#L1406 31 const float64EqualityThreshold = 1e-9 32 33 // InEpsilonF64Slices returns true if all the elements in v1 and v2 are within epsilon of each other. 34 func InEpsilonF64Slices(want, got [][]float64) bool { 35 if len(want) != len(got) { 36 return false 37 } 38 39 for i := 0; i < len(want); i++ { 40 if !InEpsilonF64Slice(want[i], got[i]) { 41 return false 42 } 43 } 44 return true 45 } 46 47 // InEpsilonF64Slice returns true if all the elements in v1 and v2 are within epsilon of each other. 48 // assert.InEpsilonSlice requires v1 to be non-zero. 49 func InEpsilonF64Slice(want, got []float64) bool { 50 if len(want) != len(got) { 51 return false 52 } 53 54 for i := 0; i < len(want); i++ { 55 if !InEpsilonF64(want[i], got[i]) { 56 return false 57 } 58 } 59 return true 60 } 61 62 // InEpsilonF64 returns true if v1 and v2 are within epsilon of each other. 63 // assert.InEpsilon requires v1 to be non-zero. 64 func InEpsilonF64(want, got float64) bool { 65 return want == got || math.Abs(want-got) < float64EqualityThreshold || (math.IsNaN(want) && math.IsNaN(got)) 66 }