我的问题 - 第1部分:测试浮点数是否为“整数”(在Matlab中)的最佳方法是什么?
我对第1部分的当前解决方案:显然,isinteger
已经出局,因为这会测试元素的类型而不是值,所以目前我解决了这样的问题:
abs(round(X) - X) <= sqrt(eps(X))
但也许有一种更原生的Matlab方法?
我的问题 - 第2部分:如果我目前的解决方案确实是最好的方法,那么我想知道是否存在推荐的一般容差?从上面可以看出,我使用sqrt(eps(X))
,但我没有任何充分的理由。也许我应该使用eps(X)
,或者5 * eps(X)
?任何建议都是最受欢迎的。
示例:在Matlab中,sqrt(2)^2 == 2
返回False。但实际上,我们可能希望逻辑条件返回True。可以使用上述方法实现这一点,因为sqrt(2)^2
实际上等于2 + eps(2)
(即在sqrt(eps(2))
的容差范围内。但这是否意味着我应该始终使用eps(X)
我的宽容度,还是有充分的理由使用更大的容差,例如5 * eps(X)
或sqrt(eps(X))
?
更新(2012-10-31): @FakeDIY指出我的问题部分与this SO question重复(道歉,不知道我在初次搜索中是如何错过的) 。鉴于此,我想强调问题的“容忍”部分(该链接未涵盖),即eps(X)
是合理的容忍度,还是应该使用更大的容差,如5 * eps(X)
,如果是的话,为什么?
更新(2012-11-01):感谢大家的回复。因为我觉得它们对问题的各个方面都有意义,所以我对所有三个答案都进行了+1。我正在给Eric Postpischil一个回答,因为这个答案确实很好地解决了问题的容忍部分(并且它在这个时间点上有最多的赞成)。
答案 0 :(得分:6)
不,建议没有一般的容差,也不能。
计算结果与数学上理想结果之间的差异是产生计算结果的操作的函数。因为这些操作特定于每个应用程序,所以没有通用规则来测试计算结果的任何属性。
要设计正确的测试,您必须确定计算过程中可能发生的错误,确定计算结果中产生的错误的界限,并测试计算结果是否与理想结果(可能是最接近的整数)相差较少比那些界限。您还必须确定这些边界是否足够小以满足您的应用程序的要求。 (使用宽松的测试,接受整数不是整数的东西会减少错误的否定[错误地拒绝结果作为理想结果为整数的整数]但会增加误报[结果的错误接受为整数其中理想的结果不是整数]。)
(注意甚至可能是测试好像错误界限为零会产生错误否定:当理想结果不是整数时,计算可能产生的结果恰好是整数,所以任何错误容忍,即使为零,也会错误地报告此结果是一个整数。如果这对您的应用程序来说是不可接受的,那么在这种情况下,必须重新设计计算。)
如果没有应用程序的具体知识,不仅无法说明可能使用的数值公差,也无法说明公差是绝对的,应该是相对于计算值还是相对于目标值,应以ULP(最低精度单位)来衡量,或者应以其他方式设定。这是因为可以以各种方式将错误引入计算中。例如,如果a
中存在较小的相对错误且a
且b
的值接近,则a-b
的相对误差较大。此外,如果c
很大,则(a-b)*c
的绝对误差很大。
答案 1 :(得分:3)
它可能不是最有效的方法,但我会使用mod
:
a = 15.0000000000;
b = mod(a,1.0)
c = 15.0000000001;
d = mod(c,1.0)
返回b = 0
和d = 1.0000e-010
这里提出了许多其他选择:
How do I test for integers in MATLAB?
我也喜欢比较(x == floor(x))
的想法。
答案 2 :(得分:1)
1)我历来使用您的方法使用简单的容差eps(X)
。 mod方法虽然让我感兴趣,所以我使用Steve Eddins timeit函数对一对夫妇进行了基准测试。
f = @() abs(X - round(X)) <= eps(X);
g = @() X == round(X);
h = @() ~mod(X,1);
对于单个值,例如X=1.0
,您的似乎最快:
timeit(f) = 7.3635e-006
timeit(g) = 9.9677e-006
timeit(h) = 9.9214e-006
对于向量,如X = 1:0.01:100
,其他方法更快(虽然圆形仍然是节拍模式):
timeit(f) = 0.00076636
timeit(g) = 0.00028182
timeit(h) = 0.00040539
2)错误界限实际上是依赖于问题的。其他答案比我能够做得更好。