This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
Everywhere within my code when I interact with a float value in my database, I always round(); it to 2 decimals in PHP, how come I get values like this: 0.00000305176 within my database sometimes?
As far as I know, most, if not all programming languages suffer from this particular issue and the reason is, non-technically put because the machine uses a binary system to work through operations, from what I understand, while we expect a result in a decimal system.
If I understand it correctly the language has no way to precisely represent values such as 0.1, 0.2, or so, because it doesn't understand decimals like we do.
While we have decimal increases on 10s, 100s and 1000, to represent in a power mathematically it is 10^1, 10^2, 10^3, decimals go same way 10^-1, 10^-2, 10^-3, representing 0.1, 0.01 and 0.001.
However in binary the base is 2 not 10, so the same power exponent applies, you'd get 2, 4, 8, and in decimal you'd get 0.5, 0.25, 0.125 , 0.0625. So you see, it is hard for a machine to get an exact 0.1, it can get close though.
More about this in this article
Related
This question already has answers here:
When should I use double instead of decimal?
(12 answers)
Closed 9 years ago.
I keep seeing people using doubles in C#. I know I read somewhere that doubles sometimes lose precision.
My question is when should a use a double and when should I use a decimal type?
Which type is suitable for money computations? (ie. greater than $100 million)
For money, always decimal. It's why it was created.
If numbers must add up correctly or balance, use decimal. This includes any financial storage or calculations, scores, or other numbers that people might do by hand.
If the exact value of numbers is not important, use double for speed. This includes graphics, physics or other physical sciences computations where there is already a "number of significant digits".
My question is when should a use a
double and when should I use a decimal
type?
decimal for when you work with values in the range of 10^(+/-28) and where you have expectations about the behaviour based on base 10 representations - basically money.
double for when you need relative accuracy (i.e. losing precision in the trailing digits on large values is not a problem) across wildly different magnitudes - double covers more than 10^(+/-300). Scientific calculations are the best example here.
which type is suitable for money
computations?
decimal, decimal, decimal
Accept no substitutes.
The most important factor is that double, being implemented as a binary fraction, cannot accurately represent many decimal fractions (like 0.1) at all and its overall number of digits is smaller since it is 64-bit wide vs. 128-bit for decimal. Finally, financial applications often have to follow specific rounding modes (sometimes mandated by law). decimal supports these; double does not.
According to Characteristics of the floating-point types:
.NET Type
C# Keyword
Precision
System.Single
float
~6-9 digits
System.Double
double
~15-17 digits
System.Decimal
decimal
28-29 digits
The way I've been stung by using the wrong type (a good few years ago) is with large amounts:
£520,532.52 - 8 digits
£1,323,523.12 - 9 digits
You run out at 1 million for a float.
A 15 digit monetary value:
£1,234,567,890,123.45
9 trillion with a double. But with division and comparisons it's more complicated (I'm definitely no expert in floating point and irrational numbers - see Marc's point). Mixing decimals and doubles causes issues:
A mathematical or comparison operation
that uses a floating-point number
might not yield the same result if a
decimal number is used because the
floating-point number might not
exactly approximate the decimal
number.
When should I use double instead of decimal? has some similar and more in depth answers.
Using double instead of decimal for monetary applications is a micro-optimization - that's the simplest way I look at it.
Decimal is for exact values. Double is for approximate values.
USD: $12,345.67 USD (Decimal)
CAD: $13,617.27 (Decimal)
Exchange Rate: 1.102932 (Double)
For money: decimal. It costs a little more memory, but doesn't have rounding troubles like double sometimes has.
Definitely use integer types for your money computations.
This cannot be emphasized enough since at first glance it might seem that a floating point type is adequate.
Here an example in python code:
>>> amount = float(100.00) # one hundred dollars
>>> print amount
100.0
>>> new_amount = amount + 1
>>> print new_amount
101.0
>>> print new_amount - amount
>>> 1.0
looks pretty normal.
Now try this again with 10^20 Zimbabwe dollars:
>>> amount = float(1e20)
>>> print amount
1e+20
>>> new_amount = amount + 1
>>> print new_amount
1e+20
>>> print new_amount-amount
0.0
As you can see, the dollar disappeared.
If you use the integer type, it works fine:
>>> amount = int(1e20)
>>> print amount
100000000000000000000
>>> new_amount = amount + 1
>>> print new_amount
100000000000000000001
>>> print new_amount - amount
1
I think that the main difference beside bit width is that decimal has exponent base 10 and double has 2
http://software-product-development.blogspot.com/2008/07/net-double-vs-decimal.html
This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
In php arithmetic operation
<?php
$lower = floor(63.1);
$value = 63.1;
echo $value - $lower;die; ?>
i get the answer as 0.1, but when i do the same for
64.1-64 i get the result as
0.099999999999994
Why is it so?
It's a problem that many languages, not just PHP have, when running on hardware (like most hardware) that supports floating point in binary or base-2 (base-16 as a shorthand) but not in base-10 that we humans use (and often assume is the only way to represent numbers).
0.1 to us humans is a base-10 notation which means 1 x 10**-1. This cannot be represented accurately in base-16. Closest is 9 x 16**-2 + 9 x 16**-3 ...
Base-10 has this problem in reverse. Base-10 represents the fraction 1/3 as 0.333333... But if we were using base-3, it would be a succinct 0.1 = 1 x 3**-1.
In PHP, if you need better base-10 precision, use the BC Math functions.
(Note some hardware can represent numbers in base-10. Mainframes, for example, for 50+ years have "packed decimal" and the corresponding native opcodes to process this. Not surprising, as they were built as business machines for accurately handling base-10 things like money!).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is double Multiplication Broken in .NET?
PHP unexpected result of float to int type cast
echo (int) ( (0.1+0.7) * 10);
Gives me answer 7 but not 8.
echo (int) ( (0.1+0.8) * 10);
Gives answer 9 which is right
whats wrong? can anybody explain
thanx,
-Navi
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
try
echo (float) ( (0.1+0.7) * 10);
Use Float
echo (float) ( (0.1+0.7) * 10);
it will give you perfect ans
try
echo (int) round( ( (0.1+0.7) * 10));
This should compensate the floating point computation error.
24151.40 - 31891.10 = -7739.699999999997
I grab these two numbers from a MySQL table with the type as decimal(14,2)
24151.40
31891.10
It is saved exactly as stated above and it echos exactly like that in PHP. But the minute I subtract the second value from the first value, I get a number -7739.699999999997 instead of -7,739.7. Why the extra precision? And where is it coming from?
From an article I wrote for Authorize.Net:
One plus one equals two, right? How about .2 plus 1.4 times 10? That equals 16, right? Not if you're doing the math with PHP (or most other programming languages):
echo floor((0.2 + 1.4) * 10); // Should be 16. But it's 15!
This is due to how floating point numbers are handled internally. They are represented with a fixed number of decimal places and can result in numbers that do not add up quite like you expect. Internally our .2 plus 1.4 times 10 example computes to roughly 15.9999999998 or so. This kind of math is fine when working with numbers that do not have to be precise like percentages. But when working with money precision matters as a penny or a dollar missing here or there adds up quickly and no one likes being on the short end of any missing money.
The BC Math Solution
Fortunately PHP offers the BC Math extension which is "for arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings." In other words, you can do precise math with monetary values using this extension. The BC Math extension contains functions that allow you to perform the most common operations with precision including addition, subtraction, multiplication, and division.
A Better Example
Here's the same example as above but using the bcadd() function to do the math for us. It takes three parameters. The first two are the values we wish to add and the third is the number of decimal places we wish to be precise to. Since we're working with money we'll set the precision to be two decimal palces.
echo floor(bcadd('0.2', '1.4', 2) * 10); // It's 16 like we would expect it to be.
PHP doesn't have a decimal type like MySQL does, it uses floats; and floats are notorious for being inaccurate.
To cure this, look into number_format, e.g.:
echo number_format(24151.40 - 31891.10, 2, '.', '');
For more accurate number manipulation, you could also look at the math extensions of PHP:
http://www.php.net/manual/en/refs.math.php
This has to do with general float / double precision rates, which scientifically relates to 1.FRACTAL * 2^exponential power. Being that there's a prefix of 1, there's technically no such thing as zero, and the closest value you can obtain to 0 is 1.0 * 2 ^ -127 which is .000000[127 0s]00001
By rounding off your answer to a certain precision, the round factor will give you a more precise answer
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_round
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
PHP unexpected result of float to int type cast
int((0.1+0.7)*10) = 7 in several languages. How to prevent this?
Can someone explain me this???
<?php
echo (int) ((0.1 + 0.7)*10);//displays an output: `7`
?>
I was expecting to see 8 but I got 7 - please explain this behavior.
Is this a special feature from PHP? Or I didn't understand the integer type in PHP?
Thanks.
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....