为什么比较双精度和单精度会导致意想不到的结果?

52 浏览
0 Comments

为什么比较双精度和单精度会导致意想不到的结果?

这个问题已经在这里有了答案

可能重复:

在将float与float文字进行比较时输出奇怪

float f = 1.1;
double d = 1.1;
if(f == d) // returns false!

为什么会这样?

admin 更改状态以发布 2023年5月22日
0
0 Comments

尝试运行此代码,结果将使原因显而易见。

#include 
#include 
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。当您尝试进行比较时,浮点数会被隐式地上转换为双精度。双精度数据类型可以准确地表示浮点数的内容,因此比较得出false。

0
0 Comments

在考虑使用floatdouble数字时,需要考虑的重要因素有:
精度舍入


精度:
浮点数的精度是它能表示多少个数字,而不会失去它包含的任何信息。

考虑分数1/3。这个数的十进制表示为0.33333333333333…,有无数个3。一个无限长度的数字需要无限的内存才能以精确的精度表示,但floatdouble数据类型通常仅有48字节。因此,浮点数和双精度数只能存储一定数量的数字,其余的数字必定会丢失。因此,没有明确定义的准确方法可以用变量随着精度要求更高的数字来表示浮点或双精度数字。


舍入:
二进制十进制(基数为10)数字之间存在一些不明显的差异。
考虑分数1/10。在十进制中,这可以简单地表示为0.1,并且0.1可以被视为一个容易表示的数字。但是,在二进制中,0.1由无限的序列表示:0.00011001100110011…

例子:

#include 
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

0