C ++ incorrect floating point arithmetic

For the next 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 get the following output:

 1 0.5 0.333333333333333314829616256247 0.25 0.200000000000000011102230246252 0.166666666666666657414808128124 0.142857142857142849212692681249 0.125 0.111111111111111104943205418749 

Which is definitely not suitable for lower digits, especially with respect to 1 / 3,1 / 5,1 / 7 and 1/9. things start to start wrong 10 ^ -16 I would expect to see more like this:

 1 0.5 0.333333333333333333333333333333 0.25 0.2 0.166666666666666666666666666666 0.142857142857142857142857142857 0.125 0.111111111111111111111111111111 

Is this inheriting flaws in the float class? Is there a way to overcome this and have the right separation? Is there a special data type for performing precise decimal operations? Am I just doing something stupid or wrong in my example?

+4
source share
3 answers

There are many numbers that computers cannot represent, even if you use double precision float or float. 1/3 or .3 repeating is one of these numbers. Thus, he does everything possible, and this is the result that you get.

See http://floating-point-gui.de/ , or Google float accuracy, there is a ton of information (including many SO questions) on this.

To answer your questions - yes, this is an inherent restriction both in the float class and in the double class. Some math programs (MathCAD, possibly Mathematica) can perform "symbolic" math, which allows you to calculate the "correct" answers. In many cases, the rounding error can be controlled even by really complex calculations, so the upper 6-8 decimal places are correct. However, the opposite is also true: naive calculations can be constructed, which returns wildly incorrect answers.

For small tasks, such as integer division, you get a decent amount of decimal places (maybe 4-6 places). If you use a float with double precision, it can increase to 8. If you need more ... well, I would start asking why you want a lot of decimals.

+6
source

First of all, since your code does 1.0/a , it gives you double ( 1.0 is the double value, 1.0f is float ), because C ++ (and C) rules always expand the smaller type to the larger one if the operands of the operation have different size (therefore int + char makes char into int before adding values, long + int will make int long, etc. etc.).

Second floating point values ​​have a given number of bits for the "number". In float, that is 23 bits (+ 1 'hidden bit), and in double - 52 bits (+1). However, get about 3 digits per bit (exactly: log2 (10) if we use a decimal numeric representation), so a 23-bit number gives about 7-8 digits, a 53-bit number is about 16-17 digits. The rest is just β€œnoise” caused by the last few bits of a number that does not go beyond conversion to decimal.

To have infinite accuracy, we need to either save the value as a fraction, or have an infinite number of bits. And, of course, we could have some other final accuracy, for example, 100 bits, but I'm sure you will complain about it too, because it will just have about 15 more digits before it "goes wrong."

+5
source

Floats have only this precision (23 bits, to be precise). If you really want to see the result "0.333333333333333333333333333333", you can create your own class "Fraction", which stores the numerator and denominator separately. Then you can calculate the number at any given point with complete accuracy.

+2
source

Source: https://habr.com/ru/post/1481035/


All Articles