可能重复:
strange output in comparision of float with float literal
float f = 1.1;
double d = 1.1;
if(f == d) // returns false!
为什么会这样?
答案 0 :(得分:32)
float
或double
数字所考虑的重要因素是:
精确度&的舍入强>
<强>精密:强>
浮点数的精度是它可以表示的位数,而不会丢失它包含的任何信息。
考虑分数1/3
。此数字的十进制表示为0.33333333333333…
,其中3表示无穷大。无限长度数将要求以精确的精度描绘无限内存,但float
或double
数据类型通常只有4
或8
个字节。因此浮点&amp;双数字只能存储一定数量的数字,其余数字必然会丢失。因此,没有明确准确的方法来表示浮点数或双数字,其数字需要比变量可以保持的精度更高。
<强>四舍五入:强>
binary
和decimal (base 10)
数字之间存在明显差异
考虑分数1/10
。在decimal
中,这可以很容易地表示为0.1
,而0.1
可以被视为一个易于表示的数字。但是,在二进制中,0.1
由无限序列表示:0.00011001100110011…
一个例子:
#include <iomanip>
int main()
{
using namespace std;
cout << setprecision(17);
double dValue = 0.1;
cout << dValue << endl;
}
此输出为:
0.10000000000000001
而不是
0.1.
这是因为双重必须截断近似值,因为它的内存有限,导致数字不完全是0.1
。这种情况称为舍入错误。
每当比较两个关闭的浮点数和双数字时,这样的舍入错误就会启动并最终比较产生不正确的结果,这就是你不应该使用==
来比较浮点数或加倍的原因。
你能做的最好的就是区分它们并检查它是否小于epsilon。
abs(x - y) < epsilon
答案 1 :(得分:8)
尝试运行此代码,结果将使原因显而易见。
#include <iomanip>
#include <iostream>
int main()
{
std::cout << std::setprecision(100) << (double)1.1 << std::endl;
std::cout << std::setprecision(100) << (float)1.1 << std::endl;
std::cout << std::setprecision(100) << (double)((float)1.1) << std::endl;
}
输出:
1.100000000000000088817841970012523233890533447265625
1.10000002384185791015625
1.10000002384185791015625
float
和double
都不能准确表示1.1。当您尝试进行比较时,浮点数会隐式上转换为double。 double数据类型可以准确地表示float的内容,因此比较产生false。
答案 2 :(得分:4)
通常情况下,你不应该使用==
将浮点数与浮点数进行比较,双精度数转换为双精度数,或浮点数加倍数。
最佳做法是减去它们,并检查差异的绝对值是否小于小epsil。
if(std::fabs(f - d) < std::numeric_limits<float>::epsilon())
{
// ...
}
一个原因是因为浮点数是(或多或少)二进制分数,并且只能接近许多十进制数。必须将许多十进制数转换为重复的二进制“小数”或无理数。这将引入舍入误差。
例如,使用二进制基数不能将1/5精确表示为浮点数,但可以使用小数基数精确表示。
在您的特定情况下,float和double将对无理/重复分数进行不同的舍入,必须使用它来表示二进制中的1.1
。在相应的转换引入不同级别的舍入错误后,您将很难让它们“平等”。
我上面给出的代码通过简单地检查值是否在非常短的delta内来解决这个问题。您的比较是否会改变“这些值是否相等?” “这些值是否在彼此之间的误差范围内?”
另请参阅此问题:What is the most effective way for float and double comparison?
还有很多关于浮点数的奇怪之处,它们打破了简单的相等比较。查看本文以获取其中一些内容的说明:
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
答案 3 :(得分:2)
IEEE 754 32位float
可以存储:1.1000000238...
IEEE 754 64位double
可以存储:1.1000000000000000888...
看看为什么他们不“平等”?
在IEEE 754中,分数以2的幂存储:
2^(-1), 2^(-2), 2^(-3), ...
1/2, 1/4, 1/8, ...
现在我们需要一种方法来表示0.1
。这是32位IEEE 754表示(浮点)的简化版本:
2^(-4) + 2^(-5) + 2^(-8) + 2^(-9) + 2^(-12) + 2^(-13) + ... + 2^(-24) + 2^(-25) + 2^(-27)
00011001100110011001101
1.10000002384185791015625
使用64位double
,它更加准确。它不会停留在2^(-25)
,它会持续大约两倍。 (2^(-48) + 2^(-49) + 2^(-51)
,也许?)
<强>资源强>
IEEE 754 Converter(32位)
答案 4 :(得分:0)
浮点数和双精度数以二进制格式存储,不能准确表示每个数字(在有限空间中无法表示无限多个可能的不同数字)。
结果他们做了四舍五入。 Float必须舍入两倍以上,因为它更小,因此1.1舍入到最近的有效Float不同于1.1舍入到最近的valud Double。
要查看哪些数字是有效的浮点数和双打数,请参阅Floating Point