Int((0.1+0.7)*10) = 7 in Several Languages. How to Prevent This

int((0.1+0.7)*10) = 7 in several languages. How to prevent this?

What Every Computer Scientist Should Know About Floating-Point Arithmetic

int a = (int) ((0.7 + 0.1) * 10). Why a = 7?

The issue is that neither 0.1 nor 0.7 can be represented exactly as double:

  • 0.1 gets represented as approximately 0.10000000000000000555.

  • 0.7 gets represented as approximately 0.69999999999999995559.

Their sum is approximately 0.79999999999999993339. Multiplied by ten and truncated, this gives 7.

What Every Computer Scientist Should Know About Floating-Point Arithmetic is an excellent read on the subject.

Why does this code print a result of '7'?

From PHP.net

It is typical that simple decimal fractions like 0.1 or 0.7 cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9.

This is due to the fact that it is impossible to express some fractions in decimal notation with a finite number of digits. For instance, 1/3 in decimal form becomes 0.3.

PHP acting weird on my program

It is because floating point representation in computers is not exact for some numbers. As already said in the comments, 0.7 is represented internally as 0.699999 or so.

There are two websites that continuously pop up in these kind of questions:

  1. http://floating-point-gui.de/
  2. http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

I prefer the first one, as it is a little lighter on the academics. Read that information and you'll understand.

PHP (int) / braces mathematically wrong - Possible Bug?

The cast to integer (and related rounding error) occurs at a different point in the formula

Calculate 0.1 plus 0.7, multiply by 10 and cast to integer; 

with the expected rounding error, should result in 7

against

Calculate 0.1 plus 0.7, cast to integer, and multiply by 10

casting 0.1 + 0.7 (ie 0.8) to integer should give 0, which multiplied by 10 is still 0

Wrong Calculation?

It’s normal – There’s a thing called precision while working with floating point numbers. It’s present in most of the modern languages. See here: http://www.mredkj.com/javascript/nfbasic2.html for more information.

((0.1+0.7) * 10) is probably something like 7.9999999 and (int) 7.9999999 = 7

On the other hand ((0.1+0.8) * 10) is probably 9.00000001 and (int)9.00000001 = 9

Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.

Additionally, rational numbers that are exactly representable as
floating point numbers in base 10, like 0.1 or 0.7, do not have an
exact representation as floating point numbers in base 2, which is
used internally, no matter the size of the mantissa. Hence, they
cannot be converted into their internal binary counterparts without a
small loss of precision. This can lead to confusing results: for
example, floor((0.1+0.7)*10) will usually return 7 instead of the
expected 8, since the internal representation will be something like
7.9999999999999991118....

So never trust floating number results to the last digit, and do not
compare floating point numbers directly for equality. If higher
precision is necessary, the arbitrary precision math functions and gmp
functions are available.

Source: http://php.net/manual/en/language.types.float.php

Adding fractions number yields different result in PHP

This question in php manual:

Additionally, rational numbers that are exactly representable as
floating point numbers in base 10, like 0.1 or 0.7, do not have an
exact representation as floating point numbers in base 2, which is
used internally, no matter the size of the mantissa. Hence, they
cannot be converted into their internal binary counterparts without a
small loss of precision. This can lead to confusing results: for
example, floor((0.1+0.7)*10) will usually return 7 instead of the
expected 8, since the internal representation will be something like
7.9999999999999991118....

Type Casting With Arithmetic Operation

In the common double-precision format, numbers are represented with a sign bit, an 11-bit exponent, and a 53-bit fraction portion that is called a significand. The significand is always a 53-bit non-negative integer divided by 252 (which can also be written in binary as one binary digit, a radix point, and 52 more binary digits).

.1 cannot be represented exactly. It is represented with an exponent of -4 and a significand of 7205759403792794 / 252. That is, the closest double to .1 is 7205759403792794•2-52•2-4 = 0.1000000000000000055511151231257827021181583404541015625.

The closest double to .7 has a significand of 6305039478318694 / 252 and an exponent of -1; it is 6305039478318694•2-52•2-1 = 0.6999999999999999555910790149937383830547332763671875.

When you add these two numbers, the result is 0.7999999999999999611421941381195210851728916168212890625. This is also not exactly representable in a double; it has to be rounded to the nearest representable value and, when you multiply by 10, that has to be rounded again. However, you can see that the sum is less than .8. The final result is less than 8, so conversion to an integer truncates it to 7.

The double nearest .8 is 0.8000000000000000444089209850062616169452667236328125. When you add that to 0.1000000000000000055511151231257827021181583404541015625, the sum is 0.9000000000000000499600361081320443190634250640869140625. As you can see, it is greater than .9. The final result of rounding and multiplying by 10 will be 9 or greater, so conversion to an integer produces 9.

The fact that several other values you tried did not round down is merely happenstance. Every value that is not exactly representable falls somewhere between two representable values, one higher and one lower. Some are closer to the higher value and some are closer to the lower value, and you just happened to pick values that were closer to a higher representable value and were rounded upward.



Related Topics



Leave a reply



Submit