如何危险的是它比较浮点值? [英] How dangerous is it to compare floating point values?

查看:92
本文介绍了如何危险的是它比较浮点值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,因为该决议独立的UIKit 使用 CGFloat的坐标系。

I know UIKit uses CGFloat because of the resolution independent coordinate system.

但我想检查是否例如 frame.origin.x 是每次 0 这让我感到生病的:

But every time I want to check if for example frame.origin.x is 0 it makes me feel sick:

if (theView.frame.origin.x == 0) {
    // do important operation
}

不是 CGFloat的比较时容易误报== &LT = > = < &GT ;
这是一个浮点和他们未precision问题: 0.0000000000041 例如:

的Objective-C 处理这个内部比较,也可以发生时,一个 origin.x 其内容零比不上 0 为真?

Is Objective-C handling this internally when comparing or can it happen that a origin.x which reads as zero does not compare to 0 as true?

推荐答案

首先,浮点值不在他们的行为随机。精确比较能够而且确实意义在很多现实世界的用法。但是,如果你打算使用浮点数,你需要知道它是如何工作。就任浮点一边犯错的工作原理是实数,将让你code迅速打破。犯错误的假设浮点运算结果的侧面与他们(最喜欢这里的答案的建议)相关的大的随机模糊会让你出现在第一个工作,但最终有大幅度误差和破碎的角落情况下code

First of all, floating point values are not "random" in their behavior. Exact comparison can and does make sense in plenty of real-world usages. But if you're going to use floating point you need to be aware of how it works. Erring on the side of assuming floating point works like real numbers will get you code that quickly breaks. Erring on the side of assuming floating point results have large random fuzz associated with them (like most of the answers here suggest) will get you code that appears to work at first but ends up having large-magnitude errors and broken corner cases.

首先,如果你想与浮点编程,你应该阅读:

First of all, if you want to program with floating point, you should read this:

什么每个计算机科学家应该知道关于浮点运算

是的,读它的全部。如果这是太多的负担,你应该使用整数/定点为你的计算,直到你有时间去阅读它。 : - )

Yes, read all of it. If that's too much of a burden, you should use integers/fixed point for your calculations until you have time to read it. :-)

现在,随着中说,有确切的浮点比较的最大问题归结为:

Now, with that said, the biggest issues with exact floating point comparisons come down to:


  1. 这是很多价值,你可以在源写,或者用 scanf函数的strtod 不存在的浮动点值并获得默默转换为最接近近似。这是demon9733的回答在说什么。

  1. The fact that lots of values you may write in the source, or read in with scanf or strtod, do not exist as floating point values and get silently converted to the nearest approximation. This is what demon9733's answer was talking about.

这许多成果,由于没有足够的precision重新present实际结果获得圆润的事实。一个简单的例子,你可以看到这是在加入 X = 0x1fffffe Y = 1 为浮动。在这里, X 在尾数precision 24位(OK)和刚刚1位,但是当你添加它们,它们的位不重叠的地方,其结果将需要precision 25位。相反,它被(在默认的舍入模式为 0x2000000 )四舍五入。

The fact that many results get rounded due to not having enough precision to represent the actual result. An easy example where you can see this is adding x = 0x1fffffe and y = 1 as floats. Here, x has 24 bits of precision in the mantissa (ok) and y has just 1 bit, but when you add them, their bits are not in overlapping places, and the result would need 25 bits of precision. Instead, it gets rounded (to 0x2000000 in the default rounding mode).

这是很多结果,由于需要正确的价值无限多的地方获得圆润的事实。这包括像1/3既有理性的结果(这你熟悉的十进制它需要无限多的地方),但也1/10(这也需要以二进制无限多的地方,因为5不是2的幂)以及像任何事物的平方根,这不是一个完美的正方形非理性的结果。

The fact that many results get rounded due to needing infinitely many places for the correct value. This includes both rational results like 1/3 (which you're familiar with from decimal where it takes infinitely many places) but also 1/10 (which also takes infinitely many places in binary, since 5 is not a power of 2), as well as irrational results like the square root of anything that's not a perfect square.

双舍入。在某些系统(尤其是86),浮点前pressions更高的precision比他们的名义类型进行评估。这意味着,当上述类型的四舍五入的情况发生,你会得到两个舍入步骤,首先一个结果到higher- precision类型的舍入,然后舍入到最后的类型。作为一个例子,考虑小数会发生什么,如果你轮1.49的整数(1),与如果首先它圆到小数点后一位(1.5)会发生什么,然后一轮结果一个整数(2)。这实际上是在浮点处理最恶劣的地区之一,因为编译器的行为(尤其是越野车,不符合像GCC编译器)是联合国predictable。

Double rounding. On some systems (particularly x86), floating point expressions are evaluated in higher precision than their nominal types. This means that when one of the above types of rounding happens, you'll get two rounding steps, first a rounding of the result to the higher-precision type, then a rounding to the final type. As an example, consider what happens in decimal if you round 1.49 to an integer (1), versus what happens if you first round it to one decimal place (1.5) then round that result to an integer (2). This is actually one of the nastiest areas to deal with in floating point, since the behaviour of the compiler (especially for buggy, non-conforming compilers like GCC) is unpredictable.

超越函数( TRIG EXP 日志等)没有指定给具有正确舍入的结果;结果只是规定是正确的一个单位内precision的最后的地方(通常被称为 1ulp )。

Transcendental functions (trig, exp, log, etc.) are not specified to have correctly rounded results; the result is just specified to be correct within one unit in the last place of precision (usually referred to as 1ulp).

当你写浮点code,你需要记住你和可能导致的结果是不准确的数字做什么,并做出相应的比较。很多时候,它会是有意义的同一个小量比较,但小量应基于在的数字幅度所比较的,而不是绝对恒定。 (在情况下是绝对不变小量会的工作,这是强烈的指示是固定点,而不是浮点,是这个职位的最佳工具!)

When you're writing floating point code, you need to keep in mind what you're doing with the numbers that could cause the results to be inexact, and make comparisons accordingly. Often times it will make sense to compare with an "epsilon", but that epsilon should be based on the magnitude of the numbers you are comparing, not an absolute constant. (In cases where an absolute constant epsilon would work, that's strongly indicative that fixed point, not floating point, is the right tool for the job!)

编辑:特别是,相对大小厄普西隆检查应该是这个样子:

In particular, a magnitude-relative epsilon check should look something like:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))

其中, FLT_EPSILON float.h时常数(与 DBL_EPSILON <替换/ code>为双击 s或 LDBL_EPSILON 长双 S)和 K 是您选择这样的计算的累积误差肯定是由 K 单位在最后的地方(如果你不知道你得到了误差界计算正确,做出比你的计算说,这应该是更大 K 几次)

Where FLT_EPSILON is the constant from float.h (replace it with DBL_EPSILON fordoubles or LDBL_EPSILON for long doubles) and K is a constant you choose such that the accumulated error of your computations is definitely bounded by K units in the last place (and if you're not sure you got the error bound calculation right, make K a few times bigger than what your calculations say it should be).

最后,请注意,如果你使用这个,可能需要一些特别的照顾接近零,因为 FLT_EPSILON 对于非正规就没有意义了。一个快速的解决将是使它:

Finally, note that if you use this, some special care may be needed near zero, since FLT_EPSILON does not make sense for denormals. A quick fix would be to make it:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)

和同样的替代品 DBL_MIN 如果使用双打。

and likewise substitute DBL_MIN if using doubles.

这篇关于如何危险的是它比较浮点值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆