简体   繁体   English

c ++不正确的浮点运算

[英]c++ incorrect floating point arithmetic

For the following program: 对于以下程序:

#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;
}

I recieve the following output: 我收到以下输出:

1
0.5
0.333333333333333314829616256247
0.25
0.200000000000000011102230246252
0.166666666666666657414808128124
0.142857142857142849212692681249
0.125
0.111111111111111104943205418749

Which is definitely not right right for the lower place digits, particularly with respect to 1/3,1/5,1/7, and 1/9. 对于较低位的数字,这绝对不是正确的,特别是对于1 / 3,1 / 5,1 / 7和1/9。 things just start going wrong around 10^-16 I would expect to see out put more resembling: 事情刚开始出错10 ^ -16我希望看到更多类似的东西:

1
0.5
0.333333333333333333333333333333
0.25
0.2
0.166666666666666666666666666666
0.142857142857142857142857142857
0.125
0.111111111111111111111111111111

Is this an inherit flaw in the float class? 这是float类中的继承缺陷吗? Is there a way to overcome this and have proper division? 有没有办法克服这个并进行适当的划分? Is there a special datatype for doing precise decimal operations? 是否有用于执行精确十进制运算的特殊数据类型? Am I just doing something stupid or wrong in my example? 在我的例子中,我只是做了一些愚蠢或错误的事情吗?

There are a lot of numbers that computers cannot represent, even if you use float or double-precision float. 计算机无法表示很多数字,即使您使用浮点数或双精度浮点数也是如此。 1/3, or .3 repeating, is one of those numbers. 1/3,或.3重复,是这些数字之一。 So it just does the best it can, which is the result you get. 所以它只是尽力而为,这就是你得到的结果。

See http://floating-point-gui.de/ , or google float precision, there's a ton of info out there (including many SO questions) on this subject. 请参阅http://floating-point-gui.de/或google float precision,这里有大量的信息(包括许多SO问题)。

To answer your questions -- yes, this is an inherent limitation in both the float class and the double class. 回答你的问题 - 是的,这是float类和double类的固有限制。 Some mathematical programs (MathCAD, probably Mathematica) can do "symbolic" math, which allows calculation of the "correct" answers. 一些数学程序(MathCAD,可能是Mathematica)可以进行“符号”数学运算,从而可以计算出“正确”的答案。 In many cases, the round-off error can be managed, even over really complex computations, such that the top 6-8 decimal places are correct. 在许多情况下,即使在非常复杂的计算中也可以管理舍入误差,使得前6-8位小数是正确的。 However, the opposite is true as well -- naive computations can be constructed that return wildly incorrect answers. 然而,情况恰恰相反 - 可以构建天真的计算,返回非常不正确的答案。

For small problems like division of whole numbers, you'll get a decent number of decimal place accuracy (maybe 4-6 places). 对于像整数除法这样的小问题,你会获得相当数量的小数位精度(可能是4-6位)。 If you use double precision floats, that will go up to maybe 8. If you need more... well, I'd start questioning why you want that many decimal places. 如果你使用双精度浮点数,那么可能会达到8个。如果你需要更多...好吧,我会开始质疑为什么你需要那么多小数位。

First of all, since your code does 1.0/a , it gives you double ( 1.0 is a double value, 1.0f is float ) as the rules of C++ (and C) always extends a smaller type to the larger one if the operands of an operation is different size (so, int + char makes the char into an int before adding the values, long + int will make the int long, etc, etc). 首先,由于你的代码是1.0/a ,它给你double1.0double值, 1.0ffloat )因为C ++(和C)的规则总是将较小的类型扩展为较大的类型,如果操作数为一个操作是不同的大小(因此, int + char在添加值之前将char变为intlong + int将使int长等等)。

Second floating point values have a set number of bits for the "number". 第二个浮点值具有“数字”的设定位数。 In float, that is 23 bits (+ 1 'hidden' bit), and in double it's 52 bits (+1). 在float中,即23位(+ 1'隐藏'位),并且在double中它是52位(+1)。 Yet get approximately 3 digits per bit (exactly: log2(10), if we use decimal number representation), so a 23 bit number gives approximately 7-8 digits, a 53 bit number approximately 16-17 digits. 然而,每位得到大约3位数(正好:log2(10),如果我们使用十进制数表示),所以23位数字给出大约7-8位数字,53位数字大约16-17位数字。 The remainder is just "noise" caused by the last few bits of the number not evening out when converting to a decimal number. 剩下的只是“噪音”,由转换为十进制数字后数字的最后几位引起。

To have infinite precision, we would have to either store the value as a fraction, or have an infinite number of bits. 要具有无限精度,我们必须将值存储为分数,或者具有无限数量的位。 And of course, we could have some other finite precision, such as 100 bits, but I'm sure you'd complain about that too, because it would just have another 15 or so digits before it "goes wrong". 当然,我们可以有一些其他有限的精度,比如100位,但我相信你也会抱怨它,因为它会在“出错”之前再有15个左右的数字。

Floats only have so much precision (23 bits worth to be precise). 浮点只有很高的精度(23位值得精确)。 If you REALLY want to see "0.333333333333333333333333333333" output, you could create a custom "Fraction" class which stores the numerator and denominator separately. 如果你真的想看到“0.333333333333333333333333333333”输出,你可以创建一个自定义的“分数”类,它分别存储分子和分母。 Then you could calculate the digit at any given point with complete accuracy. 然后,您可以完全准确地计算任何给定点的数字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM