PHP float calculation error when subtracting

php float comparison
int to float php
php float constant
php float division
php max float
how to declare float variable in php
php number format float
php round

I have a very strange issue. If I subtract 2 float vars where one is the result of a mathematical operation I get a wrong value.

Example:

var_dump($remaining);
var_dump($this->hours_sub['personal']);
echo $remaining-$this->hours_sub['personal'];

This it the output:

float 5.4
float 1.4
5.3290705182008E-15

5.4-1.4 should be 4 If I add the two values the result is correct.

Where is my mistake? It can not be a rounding issue.

If still somebody reach this page with similar problems where floating number subtraction causes error or strange values. I want to explain this problem with a bit more details.

It is not directly related to PHP and it is not a bug. However, every programmer should be aware of this issue.

This problem even took many lives two decades ago.

On 25 February 1991 this problem in floating number calculation in a MIM-104 Patriot missile battery prevented it intercepting an incoming Scud missile in Dhahran, Saudi Arabia, contributing to the death of 28 soldiers from the U.S. Army's 14th Quartermaster Detachment.

But why it happens?

The reason is that floating point values represent a limited precision. So, a value might not have the same string representation after any processing. It also includes writing a floating point value in your script and directly printing it without any mathematical operations.

Just a simple example:

$a = '36';
$b = '-35.99';
echo ($a + $b);

You would expect it to print 0.01, right? But it will print a very strange answer like 0.009999999999998

Like other numbers, floating point numbers double or float is stored in memory as a string of 0's and 1's. How floating point differs from integer is in how we interpret the 0's and 1's when we want to look at them. There are many standards how they are stored.

Floating-point numbers are typically packed into a computer datum as the sign bit, the exponent field, and the significand or mantissa, from left to right....

Decimal numbers are not well represented in binary due to lack of enough space. So, you can't express 1/3 exactly as it's 0.3333333..., right? Why we can't represent 0.01 as a binary float number is for the same reason. 1/100 is 0.00000010100011110101110000..... with a repeating 10100011110101110000.

If 0.01 is kept in simplified and system-truncated form of 01000111101011100001010 in binary, when it is translated back to decimal, it would be read like 0.0099999.... depending on system (64bit computers will give you much better precision than 32-bits). Operating system decides in this case whether to print it as it sees or how to make it in more human-readable way. So, it is machine-dependent how they want to represent it. But it can be protected in language level with different methods.

If you format the result using

echo number_format(0.009999999999998, 2);

it will print 0.01.

It is because in this case you instruct how it should be read and how precision you require.

Note number_format() is not the only function, a few other functions and ways can be used to tell the programming language about the precision expectation.

PHP. result of the subtraction of two floating point numbers, None of the numbers in your code can be expressed exactly in binary floating point. They have all been rounded somehow. The question is  PHP can only represent either 32 bit or 64 bit integers (depending on your install). So if an integer exceeds the size of the native int type (2.1 billion for 32bit, 9.2 x10^18, or 9.2 billion billion for signed ints), PHP will convert the int into a float.

In addition to using number_format(), there are three other ways to obtain the correct result. One involves doing a little math, as follows:

<?php

$a = '36';
$b = '-35.99';

$a *= 100;
$b *= 100;

echo (($a + $b)/100),"\n";

See demo

Or, you could simply use printf():

<?php

$a = '36';
$b = '-35.99';

printf("\n%.2f",($a+$b));

See demo

Note, without the precision specifier, the printf() result will contain trailing zero decimals, as follows: 0.010000

You also could also utilize the BC Math function bcadd(), as follows:

<?php
$a = '36';
$b = '-35.99';
echo "\n",bcadd($a,$b,2);

See demo

Floating point numbers - Manual, Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded​. @David: give them an example where floating point numbers are exact, such as adding 0.25 multiple times. The result will be exact until you overflow the mantissa, because 0.25 is 1/(2^2) . Then try the same thing with 0.2 and you will get the problems, because 0.2 isn't representable in a finite base-2 number.

This worked for me:

<?php
    $a = 96.35;
    $b = 96.01;

    $c = ( ( floor($a * 100) - floor($b * 100) ) / 100 );

    echo $c; // should see 0.34 exactly instead of 0.33999999999999
?>

Since the problem occurs with floating point subtraction operation I decided to eliminate that by transforming it into an integer operation, then backing up the result into a floating point again.

I much prefer that solution because basically it does prevent the error on calculation rather than rouding up the result with other functions.

Don't Trust PHP Floating Point Numbers When Equating, Don't Trust PHP Floating Point Numbers When Equating. 1 December 2013. Earlier this week I came across a bug in some code that highlighted the Computers tend to use binary numbers as it is faster to perform calculations with, and in  Again, PHP knows what is inside of the variables called $second_number and $first_number. It knows this because you assigned values to these variables in the first two lines. When PHP comes across the minus sign, it does the subtraction for you, and puts the answer into the variable on the left of the equals sign.

The PHP floating point precision is wrong by default, We have set the "precision" of the representation of PHP floating which results in a small rounding error even before the calculation happens. 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

Tutorial: Subtracting numbers using PHP., This is a beginners tutorial on how to do basic subtraction in PHP. The aim of this To subtract numbers in PHP, we use the Subtraction Arithmetic Operator. Have a look Note that in this case, the $result variable will be a float value. This is  Introduced in PHP 5.6. The division operator ("/") returns a float value unless the two operands are integers (or strings that get converted to integers) and the numbers are evenly divisible, in which case an integer value will be returned.

PHP float calculation error when subtracting, I have a very strange issue. If I subtract 2 float vars where one is the result of a mathematical operation I get a wrong value. Example: var_dump($remaining)  When numbers of different magnitudes are involved, digits of the smaller-magnitude number are lost. As an extreme example, if you have a single-precision floating point value of 100,000,000 and add 1 to it, the value will not change - even if you do it 100,000,000 times, because the result gets rounded back to 100,000,000 every single time.

Comments
  • It is working fine, maybe you should try bcsub()
  • Why "It can not be a rounding issue."?
  • @PatriciaShanahan Because a rounding issue would not produce a value close to 0 for the difference of two approximations to 5.4 and 1.4 respectively. A "rounding issue" would produce 3.999...9xyz or 4.000...0xyz.
  • @WouterJ At the moment, I'm not convinced the question should be closed at all. I suspect it will be TL, but I'm not sure. What I'm sure of is that it's not a dupe of what it was closed of. Not in the remotest.
  • Ia am sorry for the question. It was stupid. For everyone who has the same problem. You must cast floatvals to the to the same format using round() or number_format(). See php.net/manual/de/language.types.float.php
  • how to fix this ?
  • Decades will go and I will always say that this is an OBVIOUS BUG. We don't care if it saves with 0 and 1 combination or whetever - The inventors should had invented solution for this, without forcing us to learn custom programming for just to calculate 36-35.99 (i.e. save it as string at first and convert back to number - we just don't care. We need computer to calculate the simple things correctly, without any need to know the internals of float) .
  • I have already spent hour to just get the answer 945252744562139136 - 1, searched google several times for a code which can just get that simple answer correctly in php but haven't yet found.
  • Used your printf solution $result = sprintf("%.2f", $result);