1

Julia 中的isapprox()函数用于测试两个数字或数组是否近似相等。我希望能够测试任何所需数量的有效数字的近似相等性。正如下面的代码示例所示,近似容差以绝对值或相对(百分比)偏差的形式给出。

# Syntax
isapprox(a, b; atol = <absolute tolerance>, rtol = <relative tolerance>)

# Examples
# Absolute tolerance
julia> isapprox(10.0,9.9; atol = 0.1) # Tolerance of 0.1
true

# Relative tolerance
julia> isapprox(11.5,10.5; rtol = 0.1) # Rel. tolerance of 10%
true

julia> isapprox(11.4,10.5; rtol = 0.01) # Rel. tolerance of 1%
false

julia> isapprox(98.5, 99.4; rtol = 0.01) # Rel. tolerance of 1%
true

我在某处的论坛中读到该设置rtol = 1e-n,其中n有效数字的数量将比较有效数字。(不幸的是,我无法再次找到它。)无论如何,正如示例所示,这显然不是真的。

鉴于我们在这种情况下希望用两位有效数字近似相等,因此 11.4 和 10.5 都大约等于 11。但是,两者之间的相对差异大于 1%,返回近似值false。但是,对于任何大于 90 的数字,近似值为true。如代码所示,将相对容差增加十倍至 10% 将导致灵敏度过低。

是否有一个参数/值/公式我可以设置rtol为正确isapprox()返回true任何所需数量的有效数字?

4

3 回答 3

5

快速回答是否定的,没有固定值rtol可以选择,以保证isapprox(x, y; rtol=rtol)比较值xy一定数量的有效数字。这是因为如何isapprox实现:rtol是相对于 和 的最大值计算的。您必须为每对计算一个不同的值并进行比较。norm(x)norm(y)rtolxy

您所要求的似乎是一种比较xy 四舍五入到一定数量的有效数字(以 10 为基数)的值的方法。该round方法有一个sigdigits可能有用的关键字:

isapproxsigfigs(a, b, precision) = round(a, sigdigits=precision) == round(b, sigdigits=precision)

isapproxsigfigs(10, 9.9, 1)  # true,  10 == 10
isapproxsigfigs(10, 9.9, 2)  # false, 10 != 9.9

isapproxsigfigs(11.4, 10.5, 1)  # true,  10 == 10
isapproxsigfigs(11.4, 10.5, 2)  # false, 11 != 10 (remember RoundingMode!)

isapproxsigfigs(11.4, 10.51, 1)  # true,  10 == 10
isapproxsigfigs(11.4, 10.51, 2)  # true,  11 == 11
isapproxsigfigs(11.4, 10.51, 3)  # false, 11.4 != 10.5

对于第二个示例,请记住,如果您四舍五入,10.5 只是“几乎 11”。RoundingModeJulia 使用的默认值是RoundNearest,将平局舍入为偶数。如果您希望结缘,请使用RoundNearestTiesUp

isapproxsigfigs2(a, b, precision) = 
    round(a, RoundNearestTiesUp, sigdigits=precision) == 
    round(b, RoundNearestTiesUp, sigdigits=precision)

isapproxsigfigs2(11.4, 10.5, 2)  # true, 11 == 11
于 2021-08-06T01:30:14.967 回答
0

我认为您可能只需要为此定义自己的功能。一些棘手的细节:

  1. 你关心什么基础?
  2. 你想如何对待+0和-0?
  3. 一般跨越 0 的数字?
  4. 非规范化数字?
  5. 接近无穷大的数字?

在大多数极端情况下可能会做正确事情的快速穷人版本是对两个数字进行具有所需精度的格式化打印,然后比较字符串。

using Formatting

julia> function isapproxsigfigs(a, b, precision)
         fmt = "{:.$(precision-1)e}"
         format(fmt, a) == format(fmt, b)
       end
isapproxsigfigs (generic function with 1 method)

julia> isapproxsigfigs(pi, 3.14, 3)
true

julia> isapproxsigfigs(pi, 3.14, 4)
false

应该为基数 10 工作,始终将正数与负数视为不相等,并且可能对非规范化数字做正确的事情。您可能想要添加对无穷大和 NaN 的显式检查,因为此实现将无穷大视为相等,更糟糕的是,NaN 也视为相等。

注意:未来的读者也许可以做到

isapproxsigfigs(a, b, precision) = @sprintf("%.*e", precision, a) == @sprintf("%.*e", precision, b)

但 Julia 目前不支持.*其格式字符串中的精度规范。不过有一个 PR,所以也许 v1.7 以后会支持它

于 2021-08-05T14:05:22.887 回答
-1

您可以从NumPy获得提示并实现:

less_equal(x,y) = x <= y
isclose(x, y, atol, rtol) = less_equal(abs(x-y), atol + rtol * abs(y))

这不能很好地矢量化,因此请确保您查看allclose是否需要矢量化版本。此外, Usingrtol使其在xand上不可交换y,因此请注意这一点。

于 2021-08-05T20:46:13.713 回答