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  }