0

I'm wondering why my floats are not rounding. When I do that :

$shipping_cost = float(57.599999999999994) 
round($shipping_cost, 2)

The result is : 57.600000000000001

Do you have any idea why this is so ? Does it has something to do with the server ?

Thank you

Thoma Biguères
  • 1,136
  • 4
  • 18
  • 42
  • 1
    TL;DR: float math is flawed by design. In your particular case, you should use `sprintf('%.2f', $cost)` instead, as it'll give you a _string_ representation of a number. – raina77ow Feb 18 '14 at 09:26
  • The double-precision number closest to 57.599999999999994 is exactly `57.599999999999994315658113919198513031005859375`. The function `round()` is given the impossible task of creating a double-precision close to that with two digits after the dots. This double-precision number does not exist, and function `round()` should not exist since it cannot possibly do its job. It decided to return `57.60000000000000142108547152020037174224853515625`, the double closest to 57.6. – Pascal Cuoq Feb 18 '14 at 09:29
  • @raina77ow: Given that floating-point arithmetic flawed, what would you change and, specifically, what would you change it to? – Eric Postpischil Feb 18 '14 at 14:38

2 Answers2

1

This is happening due to the the way most languages represent floating point values.

1

Although you did not specify what language or implementation you are using, it is almost certainly using the IEEE-754 64-bit binary floating-point format.

In this format, finite numbers are represented as an integer f from -253 to +253 (exclusive) and two raised to some power e in the range -1074 to 971 (inclusive). Every finite floating-point value has the form f•2e. (These parts are slightly altered when encoded for storage, but this description is mathematically equivalent.)

To represent a number, it is necessary to put it into this form. For example, .75 is 3•2-2.

The value 57.6 cannot be written exactly in this form. The closest possible value is 8106479329266893•2-47 = 8106479329266893 / 140737488355328 = 57.60000000000000142108547152020037174224853515625. (You cannot get any closer to 57.6 because adding +1 or -1 to the numerator moves the value farther away from 57.6 and adding one to the exponent would make the numerator exceed 253. So this is the closest you can get within the bounds of the floating-point format.)

So that is what round(57.599999999999994, 2) returns.

When it is printed, the software you are using omits some of the digits. It appears to be printing enough digits to uniquely distinguish the exact value (somebody who knows the floating-point format can use the digits shown to figure out the exact value) but not enough to show the exact value completely.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312