Hacker News new | ask | show | jobs
by joekinley 3822 days ago
What is "unexpected" about floor(17.999999) to return 17 instead of 18?

Maybe my assumptions are wrong, and this is a truly curious question. I would ALWAYS expect floor to "basically" return the number in front of the ".", however close it is to another number. If you want that, you should use round().

2 comments

This is the "correct" behaviour of `floor` obviously, but the unexpected part has to do with floating point accuracy and use domains.

Numbers will end up slightly lower or higher than an expected value simply due to accuracy in calculations and minor differences in input.

For example, suppose we have two UI elements, one with a width of 80% and the other expressed as a factor as 0.8. Depending on how specifically these are parsed and processed this may result in slightly different values. For the user creating the UI however they'd expect the same result.

The epsilons I introduce into my floor/ceil code is meant to deal with these minor variations.

I think another contributor to the author's surprise is this subtle detail about the behavior of Python's `print` statement. From the docs[1]:

Python only prints a decimal approximation to the true decimal value of the binary approximation stored by the machine. If Python were to print the true decimal value of the binary approximation stored for 0.1, it would have to display

    >>> 0.1
    0.1000000000000000055511151231257827021181583404541015625

That is more digits than most people find useful, so Python keeps the number of digits manageable by displaying a rounded value instead

    >>> 0.1
    0.1
[1] https://docs.python.org/2/tutorial/floatingpoint.html
Python actually seems to show a much higher precision than other languages (higher than C's printf default I belive).

Interesting is that print can show an exact representation of any floating point value, but of course 0.1 can't be represented exactly.

Why not round everywhere? Wouldn't this resolve the issue?
Rounding to the nearest value does avoid the problem I had in the article. But we really wanted to `ceil` in this case, to guarantee an element is never smaller than a provided value (and doesn't end up as 0 size).
Maybe you need rational numbers instead of floating point numbers. Then .8 and 80/100 can be equal.
> I would ALWAYS expect floor to "basically" return the number in front of the "."

Not for negative numbers -- floor(-0.1) should be -1.