3 回答
TA贡献1810条经验 获得超4个赞
使用float或double数字考虑的重要因素是:
精度和舍入
精度:
浮点数的精度是它可以表示多少个数字而不会丢失其包含的任何信息。
考虑分数1/3。该数字的十进制表示形式是0.33333333333333…3到无穷大。无限长数将需要无限存储与精确的精度来示出,但float还是double数据类型通常仅具有4或8字节。因此,浮点数和双数只能存储一定数量的数字,其余数字势必会丢失。因此,没有确定精确的方法来表示浮点数或双精度数,其数字需要比变量可容纳的精度更高的精度。
舍入:和数字
之间没有明显差异。 考虑分数。在中,可以轻松地将表示为,并且可以将其视为易于表示的数字。但是,以二进制表示,由无限序列表示:binarydecimal (base 10)
1/10decimal0.10.10.10.00011001100110011…
一个例子:
#include <iomanip>
int main()
{
using namespace std;
cout << setprecision(17);
double dValue = 0.1;
cout << dValue << endl;
}
输出为:
0.10000000000000001
并不是
0.1.
这是因为双精度数由于其有限的内存而不得不截断近似值,从而导致数字不完全相等0.1。这种情况称为舍入误差。
每当比较两个接近的浮点数和双数时,这样的舍入错误就会出现,最终比较会产生错误的结果,这是您绝不应该比较浮点数或重复使用的原因==。
您能做的最好的就是找出它们的差,并检查其是否小于ε。
abs(x - y) < epsilon
TA贡献1783条经验 获得超4个赞
尝试运行此代码,结果将使原因显而易见。
#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数据类型可以准确表示浮点数的内容,因此比较得出false。
TA贡献1951条经验 获得超3个赞
通常,您不应该使用来比较浮点数与浮点数,双精度数与双精度数或浮点数与双精度数==。
最佳做法是将它们相减,并检查差的绝对值是否小于较小的ε。
if(std::fabs(f - d) < std::numeric_limits<float>::epsilon())
{
// ...
}
原因之一是因为浮点数(或多或少)是二进制分数,并且只能近似许多小数。必须将许多十进制数转换为重复的二进制“十进制”或无理数。这将引入舍入误差。
来自维基百科:
例如,不能使用二进制基数将1/5精确地表示为浮点数,而可以使用十进制基数精确地表示1/5。
在您的特定情况下,浮点数和双精度数对于必须用于以1.1二进制表示的非理性/重复分数的舍入将有所不同。在它们对应的转换引入了不同级别的舍入误差之后,将很难使它们“相等”。
我上面给出的代码通过简单地检查值是否在很短的增量内来解决此问题。您的比较从“这些值相等吗?”更改为 “这些值是否彼此之间的误差很小?”
另外,请参见以下问题:进行浮点和双重比较的最有效方法是什么?
浮点数还有很多其他奇怪的地方,打破了简单的相等比较。查看本文以了解其中的一些描述:
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
- 3 回答
- 0 关注
- 588 浏览
添加回答
举报