There's plenty of answers here about why floating point numbers work the way they do...
But there's little talk of arbitrary precision (Pickle mentioned it). If you want (or need) exact precision, the only way to do it (for rational numbers at least) is to use the BC Math extension (which is really just a BigNum, Arbitrary Precision implementation...
To add two numbers:
$number = '12345678901234.1234567890';
$number2 = '1';
echo bcadd($number, $number2);
will result in 12345678901235.1234567890
...
This is called arbitrary precision math. Basically all numbers are strings which are parsed for every operation and operations are performed on a digit by digit basis (think long division, but done by the library). So that means it's quite slow (in comparison to regular math constructs). But it's very powerful. You can multiply, add, subtract, divide, find modulo and exponentiate any number that has an exact string representation.
So you can't do 1/3
with 100% accuracy, since it has a repeating decimal (and hence isn't rational).
But, if you want to know what 1500.0015
squared is:
Using 32 bit floats (double precision) gives the estimated result of:
2250004.5000023
But bcmath gives the exact answer of:
2250004.50000225
It all depends on the precision you need.
Also, something else to note here. 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. While that's not immediately a problem (Since all ints smaller than the precision of the system's float are by definition directly representable as floats), if you try multiplying two together, it'll lose significant precision.
For example, given $n = '40000000002'
:
As a number, $n
will be float(40000000002)
, which is fine since it's exactly represented. But if we square it, we get: float(1.60000000016E+21)
As a string (using BC math), $n
will be exactly '40000000002'
. And if we square it, we get: string(22) "1600000000160000000004"
...
So if you need the precision with large numbers, or rational decimal points, you might want to look into bcmath...