Why are floating point numbers printed so differently? - php

It's kind of a common knowledge that (most) floating point numbers are not stored precisely (when IEEE-754 format is used). So one shouldn't do this:
0.3 - 0.2 === 0.1; // very wrong
... as it will result in false, unless some specific arbitrary-precision type/class was used (BigDecimal in Java/Ruby, BCMath in PHP, Math::BigInt/Math::BigFloat in Perl, to name a few) instead.
Yet I wonder why when one tries to print the result of this expression, 0.3 - 0.2, scripting languages (Perl and PHP) give 0.1, but "virtual-machine" ones (Java, JavaScript and Erlang) give something more similar to 0.09999999999999998 instead?
And why is it also inconsistent in Ruby? version 1.8.6 (codepad) gives 0.1, version 1.9.3 (ideone) gives 0.0999...

As for php, output is related to ini settings of precision:
ini_set('precision', 15);
print 0.3 - 0.2; // 0.1
ini_set('precision', 17);
print 0.3 - 0.2; //0.099999999999999978
This may be also cause for other languages

Floating-point numbers are printed differently because printing is done for different purposes, so different choices are made about how to do it.
Printing a floating-point number is a conversion operation: A value encoded in an internal format is converted to a decimal numeral. However, there are choices about the details of the conversion.
(A) If you are doing precise mathematics and want to see the actual value represented by the internal format, then the conversion must be exact: It must produce a decimal numeral that has exactly the same value as the input. (Each floating-point number represents exactly one number. A floating-point number, as defined in the IEEE 754 standard, does not represent an interval.) At times, this may require producing a very large number of digits.
(B) If you do not need the exact value but do need to convert back and forth between the internal format and decimal, then you need to convert it to a decimal numeral precisely (and accurately) enough to distinguish it from any other result. That is, you must produce enough digits that the result is different from what you would get by converting numbers that are adjacent in the internal format. This may require producing a large number of digits, but not so many as to be unmanageable.
(C) If you only want to give the reader a sense of the number, and do not need to produce the exact value in order for your application to function as desired, then you only need to produce as many digits as are needed for your particular application.
Which of these should a conversion do?
Different languages have different defaults because they were developed for different purposes, or because it was not expedient during development to do all the work necessary to produce exact results, or for various other reasons.
(A) requires careful code, and some languages or implementations of them do not provide, or do not guarantee to provide, this behavior.
(B) is required by Java, I believe. However, as we saw in a recent question, it can have some unexpected behavior. (65.12 is printed as “65.12” because the latter has enough digits to distinguish it from nearby values, but 65.12-2 is printed as “63.120000000000005” because there is another floating-point value between it and 63.12, so you need the extra digits to distinguish them.)
(C) is what some languages use by default. It is, in essence, wrong, since no single value for how many digits to print can be suitable for all applications. Indeed, we have seen over decades that it fosters continuing misconceptions about floating-point, largely by concealing the true values involved. It is, however, easy to implement, and hence is attractive to some implementors. Ideally, a language should by default print the correct value of a floating-point number. If fewer digits are to be displayed, the number of digits should be selected only by the application implementor, hopefully including consideration of the appropriate number of digits to produce the desire results.
Worse, some languages, in addition to not displaying the actual value or enough digits to distinguish it, do not even guarantee that the digits produced are correct in some sense (such as being the value you would get by rounding the exact value to the number of digits shown). When programming in an implementation that does not provide a guarantee about this behavior, you are not doing engineering.

PHP automatically rounds the number to an arbitrary precision.
Floating-point numbers in general aren't accurate (as you noted), and you should use the language-specific round() function if you need a comparison with only a few decimal places. Otherwise, take the absolute value of the equation, and test they are within a given range.
PHP Example from php.net:
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if(abs($a - $b) < $epsilon) {
echo "true";
}
As for the Ruby issue, they appear to be using different versions. Codepad uses 1.8.6, While Ideaone uses 1.9.3, but it's more likely related to a config somewhere.

If we want this property
every two different float has a different printed representation
Or an even stronger one useful for REPL
printed representation shall be re-interpreted unchanged
Then I see 3 solutions for printing a float/double with base 2 internal representation into base 10
print the EXACT representation.
print enough decimal digits (with proper rounding)
print the shortest decimal representation that can be reinterpreted unchanged
Since in base two, the float number is an_integer * 2^an_exponent, its base 10 exact representation has a finite number of digits.
Unfortunately, this can result in very long strings...
For example 1.0e-10 is represented exactly as 1.0000000000000000364321973154977415791655470655996396089904010295867919921875e-10
Solution 2 is easy, you use printf with 17 digits for IEEE-754 double...
Drawback: it's not exact, nor the shortest! If you enter 0.1, you get
0.100000000000000006
Solution 3 is the best one for REPL languages, if you enter 0.1, it prints 0.1
Unfortunately it is not found in standard libraries (a shame).
At least, Scheme, Python and recent Squeak/Pharo Smalltalk do it right, I think Java too.

As for Javascript, base2 is being used internally for calculations.
> 0.2 + 0.4
0.6000000000000001
For that, Javascript can only deliver even numbers, if the resulting base2 number is not periodic.
0.6 is 0.10011 10011 10011 10011 ... in base2 (periodic), whereas 0.5 is not and therefore correctly printed.

Related

Laravel issue when printing a double field coming from the database

I have an issue with laravel or php (don´t know yet), the issue is the next:
I have a field on my database called debe which value is 3.97 as you can see below. This field is a double(11,2).
When I access to that field on my framework, for example using a dd() it returns the value correctly as you can see below.
The main problem occurs when i'm trying to print into the view, I receive the next:
I dont know why this is happening but right now the only solution that I've found is to round the value using PHP round() function.
Regards
Check this article in the official documentation:
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.
You can use the round or number_format functions to get the desired decimals

In PHP, can ceil() ever round up an even division?

I have read a bunch of questions and comments but haven't seen this mentioned, and since others may have the same question, I'm posting it here.
Considering floating point errors, is it ever possible to get a result one point higher than it should be from a ceil($a / $b) where the rest of $a / $b is 0?
If so, since I'm working with positive integers higher than 0, perhaps I should write my_ceil() where I check for $a % $b first and if it's not 0, add 0.1 to $a before calling the built-in function…
If what you appear to be asking is how to use floating points including their correct non-absolute errors in deciding a ceil outcome, the following should guide you:
1) http://www.php.net/manual/en/language.types.float.php
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 [my emphasis]. If higher
precision is necessary, the arbitrary precision math functions and gmp functions are available.
Read up
Arbitrary precision math functions : http://uk1.php.net/manual/en/ref.bc.php
And gmp : http://uk1.php.net/manual/en/ref.gmp.php
2) You are caring about floats (as the single input value) when using ceil($float) when ceil will only ever round up to the nearest integer so whatever the floating value is, is irrelevant. You may be considering using the round() function instead. which has it's own ways of dealing with the above floating point inaccuracy issue.
http://php.net/manual/en/function.round.php
To answer the original question of Considering floating point errors, is it ever possible to get a result one point higher than it should be from a ceil($a / $b) where the rest of $a / $b is 0? the answer is YES because of two points:
Float is potentially significantly inaccurate in base10 numbers, and,
You are using the wrong function to get the output you want to the precision you need. In this situation using multiple float numbers you want a function that have built in precision required, such as gmp or maths functions .
Looking at the ceil source code on github, it seems that it is dependent on your C library's ceil function.
Edit: To answer the question – YES, it (probably) can.
I guess this doesn't really have anything to do with ceil() but rather with if the division in question returns a float or integer type value.
According to http://php.net/manual/en/language.operators.arithmetic.php …
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.
So using at least one float value could produce a ceil() "error", but I should be fine with two integers.

PHP Big characteristic double cast issue [duplicate]

It's kind of a common knowledge that (most) floating point numbers are not stored precisely (when IEEE-754 format is used). So one shouldn't do this:
0.3 - 0.2 === 0.1; // very wrong
... as it will result in false, unless some specific arbitrary-precision type/class was used (BigDecimal in Java/Ruby, BCMath in PHP, Math::BigInt/Math::BigFloat in Perl, to name a few) instead.
Yet I wonder why when one tries to print the result of this expression, 0.3 - 0.2, scripting languages (Perl and PHP) give 0.1, but "virtual-machine" ones (Java, JavaScript and Erlang) give something more similar to 0.09999999999999998 instead?
And why is it also inconsistent in Ruby? version 1.8.6 (codepad) gives 0.1, version 1.9.3 (ideone) gives 0.0999...
As for php, output is related to ini settings of precision:
ini_set('precision', 15);
print 0.3 - 0.2; // 0.1
ini_set('precision', 17);
print 0.3 - 0.2; //0.099999999999999978
This may be also cause for other languages
Floating-point numbers are printed differently because printing is done for different purposes, so different choices are made about how to do it.
Printing a floating-point number is a conversion operation: A value encoded in an internal format is converted to a decimal numeral. However, there are choices about the details of the conversion.
(A) If you are doing precise mathematics and want to see the actual value represented by the internal format, then the conversion must be exact: It must produce a decimal numeral that has exactly the same value as the input. (Each floating-point number represents exactly one number. A floating-point number, as defined in the IEEE 754 standard, does not represent an interval.) At times, this may require producing a very large number of digits.
(B) If you do not need the exact value but do need to convert back and forth between the internal format and decimal, then you need to convert it to a decimal numeral precisely (and accurately) enough to distinguish it from any other result. That is, you must produce enough digits that the result is different from what you would get by converting numbers that are adjacent in the internal format. This may require producing a large number of digits, but not so many as to be unmanageable.
(C) If you only want to give the reader a sense of the number, and do not need to produce the exact value in order for your application to function as desired, then you only need to produce as many digits as are needed for your particular application.
Which of these should a conversion do?
Different languages have different defaults because they were developed for different purposes, or because it was not expedient during development to do all the work necessary to produce exact results, or for various other reasons.
(A) requires careful code, and some languages or implementations of them do not provide, or do not guarantee to provide, this behavior.
(B) is required by Java, I believe. However, as we saw in a recent question, it can have some unexpected behavior. (65.12 is printed as “65.12” because the latter has enough digits to distinguish it from nearby values, but 65.12-2 is printed as “63.120000000000005” because there is another floating-point value between it and 63.12, so you need the extra digits to distinguish them.)
(C) is what some languages use by default. It is, in essence, wrong, since no single value for how many digits to print can be suitable for all applications. Indeed, we have seen over decades that it fosters continuing misconceptions about floating-point, largely by concealing the true values involved. It is, however, easy to implement, and hence is attractive to some implementors. Ideally, a language should by default print the correct value of a floating-point number. If fewer digits are to be displayed, the number of digits should be selected only by the application implementor, hopefully including consideration of the appropriate number of digits to produce the desire results.
Worse, some languages, in addition to not displaying the actual value or enough digits to distinguish it, do not even guarantee that the digits produced are correct in some sense (such as being the value you would get by rounding the exact value to the number of digits shown). When programming in an implementation that does not provide a guarantee about this behavior, you are not doing engineering.
PHP automatically rounds the number to an arbitrary precision.
Floating-point numbers in general aren't accurate (as you noted), and you should use the language-specific round() function if you need a comparison with only a few decimal places. Otherwise, take the absolute value of the equation, and test they are within a given range.
PHP Example from php.net:
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if(abs($a - $b) < $epsilon) {
echo "true";
}
As for the Ruby issue, they appear to be using different versions. Codepad uses 1.8.6, While Ideaone uses 1.9.3, but it's more likely related to a config somewhere.
If we want this property
every two different float has a different printed representation
Or an even stronger one useful for REPL
printed representation shall be re-interpreted unchanged
Then I see 3 solutions for printing a float/double with base 2 internal representation into base 10
print the EXACT representation.
print enough decimal digits (with proper rounding)
print the shortest decimal representation that can be reinterpreted unchanged
Since in base two, the float number is an_integer * 2^an_exponent, its base 10 exact representation has a finite number of digits.
Unfortunately, this can result in very long strings...
For example 1.0e-10 is represented exactly as 1.0000000000000000364321973154977415791655470655996396089904010295867919921875e-10
Solution 2 is easy, you use printf with 17 digits for IEEE-754 double...
Drawback: it's not exact, nor the shortest! If you enter 0.1, you get
0.100000000000000006
Solution 3 is the best one for REPL languages, if you enter 0.1, it prints 0.1
Unfortunately it is not found in standard libraries (a shame).
At least, Scheme, Python and recent Squeak/Pharo Smalltalk do it right, I think Java too.
As for Javascript, base2 is being used internally for calculations.
> 0.2 + 0.4
0.6000000000000001
For that, Javascript can only deliver even numbers, if the resulting base2 number is not periodic.
0.6 is 0.10011 10011 10011 10011 ... in base2 (periodic), whereas 0.5 is not and therefore correctly printed.

Why FLOAT != FLOAT

$a = 100;
$b = 3;
$test1 = $a/ $b;
$test2 = 33.333333333333; // $test2 == $test1
var_dump(($test1 * $b)); // float(100)
var_dump(($test2 * $b)); // float(99.999999999999)
Any explanation for that ?
100/3 results in 33.3-repeating.
There is no decimal point value that will ever show it. In maths, such a number is normally shown by a little dot over the repeating value. (though I have no idea how to show that in this code box).
Refer to this wiki article to see how they are represented in various places and a much more detailed explanation that I have given here.
However, from the article here is a snippet of the summary:
In arithmetic, repeating decimal is a way of representing a rational number. Thus, a decimal representation of a number is called a repeating decimal (or recurring decimal) if at some point it becomes periodic, that is, if there is some finite sequence of digits that is repeated indefinitely. For example, the decimal representation of 1/3 = 0.3333333… or 0.3 (spoken as "0.3 repeating", or "0.3 recurring") becomes periodic just after the decimal point, repeating the single-digit sequence "3" infinitely. A somewhat more complicated example is 3227/555 = 5.8144144144…, where the decimal representation becomes periodic at the second digit after the decimal point, repeating the sequence of digits "144" indefinitely.
Now, that's the crux of your issue here, but also keep in mind (as the other two answers point out) that floats are amazingly innacurate in terms of calculations and comparisons. A quick search of this site will reveal a small army of people that have had problems with the internal representations of floats - mainly which resulted in unexpected behavior when doing comparisons.
Take a long read of the PHP warning on the float data type - again I have copied the important bit here:
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....
Not all floats can be represented exactly by processor. $a/$b is one of them.
So, $test1 != $test2 is true.
Information from PHP
Warning
Floating point precision
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.
As noted in the warning above, testing floating point values for equality is problematic, due to the way that they are represented internally. However, there are ways to make comparisons of floating point values that work around these limitations.
To test floating point values for equality, an upper bound on the relative error due to rounding is used. This value is known as the machine epsilon, or unit roundoff, and is the smallest acceptable difference in calculations.
Many thanks to all who took the time to answer my question

PHP number calculation, strange result

For the following
echo 0.02-0.01-0.06+0.05;
I got result is
6.93889390391E-18
For this one
echo -0.02+0.02;
I got result
0
I want to know why i got the different result for those to. I suppose to get two 0 result.
That's how floating point numbers work.
floating point arithmetic doesn't really correlate strongly to normal mathematical rules. For example, operations aren't associative or distributive.
floating point representations are approximations with limited precision.
this isnt a php specific thing - computers simply cant represent numbers like we conceptualize them.
When you write numerals “0.02” in source code, the compiler or interpreter uses floating-point to represent them. The most common floating-point format is IEEE 754 binary floating-point, either single-precision or double-precision.
This floating-point format cannot represent most decimal numerals exactly. For example, just as decimals cannot represent 1/3 exactly (it is approximately .3333, but any decimal numeral of finite length ends somewhere, so it differs slightly from 1/3), the binary numerals used in floating-point cannot represent 1/10 exactly (in binary, 1/10 is approximately .000110011001100110011).
Therefore, when you write “0.02-0.01-0.06+0.05”, the computer is not doing arithmetic with exactly those numbers. It is using close approximations. So the result you get is a close approximation.
If you want an exact result, you must either learn the details of floating-point arithmetic so that you can craft operations that avoid error or for which the error can be corrected or you should use only integer arithmetic. For example, if the above represented dollars amounts to be added and subtracted, you could instead store penny amounts and calculate “2-1-6+5”.
If you round it to two or three decimal places, this will fix it for you.
Hi just for someone hiting this problem, you can use the arbitrary precision functions from BCMath library
http://php.net/manual/en/ref.bc.php
echo 12606.69 + 3053.46 - 15660.15;
1.8189894035459E-12
and
echo bcadd((12606.69 + 3053.46),-15660.15);
0

Categories