英文:
Difference between InDelta and InEpsilon
问题
这两个函数的作用是相同的,都用于比较两个数值是否在一定的误差范围内。它们的区别在于计算误差的方式不同。
InDelta
函数使用的是绝对误差(absolute error)的方式,通过比较两个数值的差值是否小于给定的误差范围(delta)来判断它们是否相等。
InEpsilon
函数使用的是相对误差(relative error)的方式,通过计算两个数值的相对误差是否小于给定的误差范围(epsilon)来判断它们是否相等。
选择使用哪个函数取决于具体的使用场景。如果你更关心数值的绝对误差,即两个数值的差值是否在一定范围内,可以使用InDelta
函数。如果你更关心数值的相对误差,即两个数值的相对差值是否在一定范围内,可以使用InEpsilon
函数。
举个例子来说,如果你在进行浮点数计算时,希望比较两个数值是否在某个小范围内,可以使用InDelta
函数。而如果你在进行科学实验或者统计分析时,希望比较两个数值的相对误差是否在某个小范围内,可以使用InEpsilon
函数。
总之,选择使用哪个函数取决于你对数值比较的关注点是绝对误差还是相对误差。
英文:
From documentation:
https://godoc.org/github.com/stretchr/testify/assert#InDelta
> InDelta asserts that the two numerals are within delta of each other
https://godoc.org/github.com/stretchr/testify/assert#InEpsilon
> InEpsilon asserts that expected and actual have a relative error less than epsilon
And their code seems to be identical in purpose:
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
af, aok := toFloat(expected)
bf, bok := toFloat(actual)
if !aok || !bok {
return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
}
if math.IsNaN(af) {
return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...)
}
if math.IsNaN(bf) {
return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
}
dt := af - bf
if dt < -delta || dt > delta {
return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
}
return true
}
func calcRelativeError(expected, actual interface{}) (float64, error) {
af, aok := toFloat(expected)
if !aok {
return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
}
if af == 0 {
return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
}
bf, bok := toFloat(actual)
if !bok {
return 0, fmt.Errorf("actual value %q cannot be converted to float", actual)
}
return math.Abs(af-bf) / math.Abs(af), nil
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
actualEpsilon, err := calcRelativeError(expected, actual)
if err != nil {
return Fail(t, err.Error(), msgAndArgs...)
}
if actualEpsilon > epsilon {
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
" < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
}
return true
}
What is the difference? what are the use cases where one would be used over the other and vice versa?
答案1
得分: 15
它们是相关但不完全相同的。
InDelta
接收一个绝对值,并检查差异是否小于该值。
InEpsilon
接收一个可接受的差异百分比。
InDelta
的行为非常直观:
InDelta(t, 100, 101, 2) // 没问题
InDelta(t, 100, 103, 2) // 失败!
但有时候,你只关心实际值与期望值之间的差距不要太大。
根据期望值的大小,"不要太远"可能会对InDelta
造成困扰。
对于任何数字使用相同的delta
值可能会成为一个问题:
InDelta(t, 100, 101, 2) // 没问题,101与100的差距"不太远"
InDelta(t, 1, 2, 2) // 嗯,2与1的差距听起来"太远"了...
如果使用InEpsilon
,你可以始终使用相同的百分比:
InEpsilon(t, 100, 101, 0.02) // 没问题,接受范围为102
InEpsilon(t, 1, 2, 0.02) // 不通过...这次接受范围为1.02
总之,InEpsilon
的使用场景是丢弃小的差异(并将"小"相对于实际比较的值)。
英文:
They are related but not identical.
InDelta
receives an absolute value and checks that the difference is less than that value.
InEpsilon
receives a % of difference that would be acceptable.
The behaviour of InDelta
is quite straightforward:
InDelta(t, 100, 101, 2) // that's OK
InDelta(t, 100, 103, 2) // fail!
But sometimes, you just care that the actual value is not too far away from the expected value.
Depending on how small or large the expected value is "not too far away" might get tricky with InDelta
.
It might be a problem to use the same delta
value for any number:
InDelta(t, 100, 101, 2) // ok, 101 is "not too far away" from 100
InDelta(t, 1, 2, 2) // hm, 2 sounds "too far away" from 1...
If you use InEpsilon
, you can always use the same %:
InEpsilon(t, 100, 101, 0.02) // ok, up to 102 would be acceptable
InEpsilon(t, 1, 2, 0.02) // will not pass.. this time up to 1.02 would be acceptable
In summary, the use case for ÌnEpsilon
is to discard small differences (and making "small" relative to the actual values compared).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论