浮点与浮点文字比较的奇怪输出
float f = 0.7;
if( f == 0.7 )
printf("equal");
else
printf("not equal");
为什么输出不相等
?
为什么会出现这种情况?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
float f = 0.7;
if( f == 0.7 )
printf("equal");
else
printf("not equal");
为什么输出不相等
?
为什么会出现这种情况?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(8)
发生这种情况是因为在您的声明中
0.7 被视为双精度。尝试 0.7f 以确保该值被视为浮点数:
但正如 Michael 在下面的评论中建议的那样,您永远不应该测试浮点值的精确相等性。
This happens because in your statement
the 0.7 is treated as a double. Try 0.7f to ensure the value is treated as a float:
But as Michael suggested in the comments below you should never test for exact equality of floating-point values.
这个答案是对现有答案的补充:请注意,0.7 不能完全表示为浮点数(或双精度数)。如果它被准确地表示,那么在转换为浮点型然后再转换回双精度型时不会丢失信息,并且不会出现此问题。
甚至有人认为,对于无法准确表示的字面浮点常量,应该有一个编译器警告,特别是当标准对于是否在运行时以已设置的模式进行舍入如此模糊时那时或在编译时以另一种舍入模式。
所有可以精确表示的非整数都将
5
作为最后一个十进制数字。不幸的是,反之亦然:有些数字的最后一个十进制数字是5
,并且无法准确表示。小整数都可以精确表示,只要不进入非规范化数字的领域,除以 2 的幂即可将一个可以表示的数字转换为另一个可以表示的数字。This answer to complement the existing ones: note that 0.7 is not representable exactly either as a float (or as a double). If it was represented exactly, then there would be no loss of information when converting to float and then back to double, and you wouldn't have this problem.
It could even be argued that there should be a compiler warning for literal floating-point constants that cannot be represented exactly, especially when the standard is so fuzzy regarding whether the rounding will be made at run-time in the mode that has been set as that time or at compile-time in another rounding mode.
All non-integer numbers that can be represented exactly have
5
as their last decimal digit. Unfortunately, the converse is not true: some numbers have5
as their last decimal digit and cannot be represented exactly. Small integers can all be represented exactly, and division by a power of 2 transforms a number that can be represented into another that can be represented, as long as you do not enter the realm of denormalized numbers.首先让我们看看浮点数的内部。我取 0.1f,它是 4 字节长(binary32),十六进制它是
3D CC CC CD。
按照标准 IEEE 754 将其转换为十进制,我们必须这样做:
二进制 3D CC CC CD 是
0 01111011 1001100 11001100 11001101
这里第一位数字是符号位。 0 表示 (-1)^0 我们的数字是正数。
第二个 8 位是指数。二进制为 01111011 - 十进制为 123。但真正的指数是 123-127(始终为 127)=-4,这意味着我们需要将得到的数字乘以 2^ (-4 ).
最后 23 个字节是有效位数精度。我们将第一位乘以 1/ (2^1) (0.5),第二位乘以 1/ (2^2) (0.25),依此类推。这是我们得到的:
我们需要将所有数字(2 的幂)相加,并添加 1(按照标准,始终为 1)。这是
1,60000002384185791015625
现在让我们将这个数字乘以 2^ (-4),它来自指数。我们只需将上面的数字除以 2 四次即可:
0,100000001490116119384765625
我用的是 MS 计算器
**
现在是第二部分。从十进制转换为二进制。
**
我取数字0.1
它很容易,因为没有整数部分。第一个符号位 - 为 0。
我现在将计算指数和有效数精度。逻辑是乘以 2 个整数 (0.1*2=0.2),如果大于 1,则减去并继续。
数字是.00011001100110011001100110011,标准说我们必须向左移动才能得到1.(某物)。如您所见,我们需要 4 个班次,根据这个数字计算指数 (127-4=123)。现在有效位数精度为
10011001100110011001100(并且丢失了位)。
现在全数了。符号位0指数为123(01111011),有效位数精度为10011001100110011001100,整体为
00111101110011001100110011001100
让我们将其与上一章中的内容进行比较
00111101110011001100110011001101
如您所见,最后一位不相等。这是因为我截断了数字。 CPU 和编译器知道尾数精度之后的内容无法保留,只需将最后一位设置为 1。
First of all let look inside float number. I take 0.1f it is 4 byte long (binary32), in hex it is
3D CC CC CD.
By the standart IEEE 754 to convert it to decimal we must do like this:
In binary 3D CC CC CD is
0 01111011 1001100 11001100 11001101
here first digit is a Sign bit. 0 means (-1)^0 that our number is positive.
Second 8 bits is an Exponent. In binary it is 01111011 - in decimal 123. But the real Exponent is 123-127 (always 127)=-4, it's mean we need to multiply the number we will get by 2^ (-4).
The last 23 bytes is the Significand precision. There the first bit we multiply by 1/ (2^1) (0.5), second by 1/ (2^2) (0.25) and so on. Here what we get:
We need to add all numbers (power of 2) and add to it 1 (always 1, by standart). It is
1,60000002384185791015625
Now let's multiply this number by 2^ (-4), it's from Exponent. We just devide number above by 2 four time:
0,100000001490116119384765625
I used MS Calculator
**
Now the second part. Converting from decimal to binary.
**
I take the number 0.1
It ease because there is no integer part. First Sign bit - it is 0.
Exponent and Significand precision I will calculate now. The logic is multiply by 2 whole number (0.1*2=0.2) and if it's bigger than 1 substract and continue.
And the number is .00011001100110011001100110011, standart says that we must shift left before we get 1. (something). How you see we need 4 shifts, from this number calculating Exponent (127-4=123). And the Significand precision now is
10011001100110011001100 (and there is lost bits).
Now the whole number. Sign bit 0 Exponent is 123 (01111011) and Significand precision is 10011001100110011001100 and whole it is
00111101110011001100110011001100
let's compare it with those we have from previous chapter
00111101110011001100110011001101
As you see the lasts bit are not equal. It is because I truncate the number. The CPU and compiler know that the is something after Significand precision can not hold and just set the last bit to 1.
另一个近乎精确的问题与这个问题相关,因此晚了几年才得到答案。我认为以上答案并不完整。
为什么 fun3 和 fun4 返回一个而不返回其他?为什么 fun5 有效?
这是关于语言的。该语言表示 0.7 是双精度数,除非您使用此语法 0.7f 那么它是单精度数。因此,
双精度数 0.7 被转换为单精度值并存储在 x 中。
该语言表示我们必须提升到更高的精度,因此 x 中的单精度数会转换为双精度数,并与双精度数 0.7 进行比较。
单3f333333
双 3fe6666666666666
正如亚历山大指出的,如果该答案仍然是 IEEE 754,则单是
并且双是
与 52 位小数而不是 23 位。
就像以 10 为底的 1/3 是 0.3333333...永远一样。我们这里有一个重复模式 0110
这就是答案。
x 包含 01100110011001100110011 作为其分数,当它被转换回来时
将分数加倍是
不等于,
但在这里,
相同的位模式相互比较时不会发生这种提升。
为什么1.0有效?
在这两种情况下,分数都为零。因此,从双精度转换为单精度再转换为双精度不会损失。它精确地从单精度转换为双精度,并且两个值的位比较有效。
halfdan 投票和检查的最高答案是正确答案,这是混合精度的情况,并且您永远不应该进行等于比较。
该答案中没有显示原因。 0.7 失败,1.0 有效。没有显示为什么 0.7 失败。重复的问题 1.1 也失败了。
编辑
等于可以从这里的问题中取出,这是一个已经回答的不同问题,但它是同一个问题,并且也有“什么......”最初的震惊。
为什么一个显示小于,另一个显示不小于?当它们应该相等时。
从上面我们知道了0.7的故事。
小于。
0.6 是不同的重复模式 0011 而不是 0110。
但是当从双精度转换为单精度或一般表示时
作为单个 IEEE 754。IEEE
754 使用舍入模式,向上舍入、向下舍入或舍入到零。编译器默认会进行四舍五入。如果你还记得小学时的四舍五入 12345678,如果我想四舍五入到从顶部开始的第三位数字,它将是 12300000,但如果后面的数字是 5 或更大,则四舍五入到下一个数字 1235000,然后四舍五入。 5 是 10 的 1/2,二进制 1 中的基数(十进制)是基数的 1/2,因此如果我们要舍入的位置后面的数字是 1,则向上舍入,否则不舍入。因此,对于 0.7,我们没有向上舍入,对于 0.6,我们向上舍入。
现在很容易看出,
转换为双精度是因为 (x<0.7)
大于
所以不用讨论使用 equals 问题仍然会出现 0.7 是双精度 0.7f 是单精度,运算提升到最高精度(如果它们不同)。
Another near exact question was linked to this one, thus the years late answer. I don't think the above answers are complete.
Why did fun3 and fun4 return one and not the others? why does fun5 work?
It is about the language. The language says that 0.7 is a double unless you use this syntax 0.7f then it is a single. So
the double 0.7 is converted to a single and stored in x.
The language says we have to promote to the higher precision so the single in x is converted to a double and compared with the double 0.7.
single 3f333333
double 3fe6666666666666
As Alexandr pointed out if that answer remains IEEE 754 a single is
And double is
with 52 bits of fraction rather than the 23 that single has.
Just like 1/3rd in base 10 is 0.3333333... forever. We have a repeating pattern here 0110
And here is the answer.
x contains 01100110011001100110011 as its fraction, when that gets converted back
to double the fraction is
which is not equal to
but here
That promotion doesn't happen the same bit patterns are compared with each other.
Why does 1.0 work?
In both cases the fraction is all zeros. So converting from double to single to double there is no loss of precision. It converts from single to double exactly and the bit comparison of the two values works.
The highest voted and checked answer by halfdan is the correct answer, this is a case of mixed precision AND you should never do an equals comparison.
The why wasn't shown in that answer. 0.7 fails 1.0 works. Why did 0.7 fail wasn't shown. A duplicate question 1.1 fails as well.
Edit
The equals can be taken out of the problem here, it is a different question that has already been answered, but it is the same problem and also has the "what the ..." initial shock.
Why does one show as less than and the other not less than? When they should be equal.
From above we know the 0.7 story.
is less than.
0.6 is a different repeating pattern 0011 rather than 0110.
but when converted from a double to a single or in general when represented
as a single IEEE 754.
IEEE 754 uses rounding modes, round up, round down or round to zero. Compilers tend to round up by default. If you remember rounding in grade school 12345678 if I wanted to round to the 3rd digit from the top it would be 12300000 but round to the next digit 1235000 if the digit after is 5 or greater then round up. 5 is 1/2 of 10 the base (Decimal) in binary 1 is 1/2 of the base so if the digit after the position we want to round is 1 then round up else don't. So for 0.7 we didn't round up, for 0.6 we do round up.
And now it is easy to see that
converted to a double because of (x<0.7)
is greater than
So without having to talk about using equals the issue still presents itself 0.7 is double 0.7f is single, the operation is promoted to the highest precision if they differ.
正如其他评论者所指出的,您面临的问题是,测试浮点数之间的精确等价性通常是不安全的,因为初始化错误或计算中的舍入错误可能会引入微小的差异,从而导致 == 运算符返回 false。
更好的做法是执行类似
假设 FLT_EPSILON 已被定义为适合您的平台的适当小的浮点值。
由于舍入或初始化误差不太可能超过 FLT_EPSILON 的值,因此这将为您提供所需的可靠等效性测试。
The problem you're facing is, as other commenters have noted, that it's generally unsafe to test for exact equivalency between floats, as initialization errors, or rounding errors in calculations can introduce minor differences that will cause the == operator to return false.
A better practice is to do something like
Assuming that FLT_EPSILON has been defined as an appropriately small float value for your platform.
Since the rounding or initialization errors will be unlikely to exceed the value of FLT_EPSILON, this will give you the reliable equivalency test you're looking for.
网络上的很多答案都错误地查看浮点数之间的绝对差异,这仅对特殊情况有效,可靠的方法是查看相对差异,如下所示:
A lot of the answers around the web make the mistake of looking at the abosulute difference between floating point numbers, this is only valid for special cases, the robust way is to look at the relative difference as in below:
考虑一下:
如果(0.7 > a),这里的a是一个浮点变量,
0.7
是一个双精度常量。双精度常量0.7
大于浮点变量 a。因此,满足 if 条件并打印'Hi'
示例:
输出:
0.7000000000 0.6999999881
Consider this:
if (0.7 > a) here a is a float variable and
0.7
is a double constant. The double constant0.7
is greater than the float variable a. Hence the if condition is satisfied and it prints'Hi'
Example:
Output:
0.7000000000 0.6999999881
变量和常量中保存的指针值的数据类型不同。这是数据类型精度的差异。
如果将f变量的数据类型更改为double,它会打印equal,这是因为浮点常量存储在 >double和long中默认为非浮点型,double的精度比float高。如果你看到浮点数转换为二进制的方法就完全清楚了 转换
Pointing value saved in variable and constant have not same data types. It's the difference in the precision of data types.
If you change the datatype of f variable to double, it'll print equal, This is because constants in floating-point stored in double and non-floating in long by default, double's precision is higher than float. it'll be completely clear if you see the method of floating-point numbers conversion to binary conversion