c++不正确的浮点运算
c++ incorrect floating point arithmetic
对于以下程序:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
for (float a = 1.0; a < 10; a++)
cout << std::setprecision(30) << 1.0/a << endl;
return 0;
}
我收到以下输出:
1
0.5
0.333333333333333314829616256247
0.25
0.200000000000000011102230246252
0.166666666666666657414808128124
0.142857142857142849212692681249
0.125
0.111111111111111104943205418749
对于小数来说绝对是不正确的,特别是对于1/3、1/5、1/7和1/9。事情只是在10^-16左右开始出错,我希望看到更多的类似:
1
0.5
0.333333333333333333333333333333
0.25
0.2
0.166666666666666666666666666666
0.142857142857142857142857142857
0.125
0.111111111111111111111111111111
这是float类的继承缺陷吗?有没有办法克服这一点,实现适当的划分?是否有一种特殊的数据类型来进行精确的十进制运算?我的例子是不是做错了什么?
有很多数字是计算机无法表示的,即使你使用浮点数或双精度浮点数。1/3,或者。3重复,就是其中一个数字。所以它只是尽其所能,这就是你得到的结果。
参见http://floating-point-gui.de/,或谷歌浮点精度,有大量的信息在那里(包括许多SO问题)关于这个主题。
回答你的问题——是的,这是float类和double类的固有限制。一些数学程序(MathCAD,可能是Mathematica)可以进行"符号"数学,这允许计算"正确"答案。在许多情况下,即使在非常复杂的计算中,也可以管理舍入误差,例如小数点后6-8位是正确的。然而,反过来也是正确的——天真的计算可以被构造,返回非常不正确的答案。
对于像整数除法这样的小问题,你会得到一个不错的小数精度(可能是4-6位)。如果你使用双精度浮点数,它可能会上升到8。如果你需要更多……好吧,我开始质疑你为什么要那么多小数点后的数位。
首先,因为你的代码做了1.0/a
,它给了你double
(1.0
是double
值,1.0f
是float
),因为c++(和C)的规则总是将较小的类型扩展到较大的类型,如果操作的操作数大小不同(因此,int
+ char
在添加值之前将char
变成int
, long
+ int
将使int
变长,等等)。
第二个浮点值的"数"有一个固定的位数。在浮点数中,这是23位(+1"隐藏"位),在双精度中是52位(+1)。然而,每比特得到大约3位数字(准确地说:log2(10),如果我们使用十进制数字表示),所以一个23位的数字大约有7-8位数字,一个53位的数字大约有16-17位数字。余数只是由数字的最后几位在转换为十进制数时没有重叠引起的"噪声"。
要获得无限精度,要么必须将值存储为分数,要么必须具有无限位数。当然,我们可以有一些其他的有限精度,比如100位,但我相信你也会抱怨,因为在它"出错"之前,它只会有另外15位左右的数字。
浮点数只有这么多精度(确切地说是23位)。如果你真的想看到"0.33333333333333333333333333333333333333333333"的输出,你可以创建一个自定义的"Fraction"类,它分别存储分子和分母。这样你就可以精确地计算出任意点的数字。
- 使用双精度的浮点运算
- 将异常字符串解析为向量上的浮点运算?
- -O1改变浮点运算
- 将浮点运算与 Z3 C++ API 结合使用
- C++模运算符,使用 #define 和自己的类进行浮点运算
- 浮点运算
- 我创建了一个将雷亚尔转换为美元的程序,但浮点变量不正确
- 浮点变量不存储十进制
- 浮点运算的精度
- 为什么GDB对浮点运算的评估与C++不同
- 浮点表示似乎正确地做到了整数算术 - 原因
- C中的浮点运算出错
- 在Visual C++中,浮点运算优化会导致罕见而奇怪的行为
- 浮点常量不精确的警告
- 为什么十进制浮点运算的提议没有被 C++0x 接受?
- C++输入浮点而不是整数时的输入错误
- 为什么这个浮点运算被编译得如此奇怪(没有经过优化)
- 浮点运算结果的重现性
- c++不正确的浮点运算
- 浮点行为不正确