I was working on a Project Euler problem and discovered what looks like a bug in the floor function; with some large numbers d, floor(Int, d/9) seems to round up instead of down. I haven’t looked into it too much, but one example of this behaviour is with d = 37889062372043916:

Of course, for what I want to do, I should probably have used the ÷ operator instead of the floor function with an Int argument from the get-go. I’m curious though as to whether this is a real bug or just something that should be flagged in the documentation, which currently says

floor(T, x) converts the result to type T, throwing an InexactError if the value is not representable."

making no promises the converted value will be the true floor.

The issue here is that Float64 only has 53 mantissa bits, so not every Int can be represented exactly. d/9 converts d to a Float64, which involves some rounding:

I agree, though I’m not sure what a better version of this documentation would look like. Perhaps it could be more explicit in specifying that floor(T, x) is simply defined as convert(T, x), so one can refer to the documentation for the latter for more information on how that’s implemented.

If T is an Integer type, an InexactError will be raised if x is not representable by T, for example if x is not integer-valued, or is outside the range supported by T.

but

If T is a AbstractFloat or Rational type, then it will return the closest value to x representable by T.

What is the rationale behind this “sometimes lossy, sometimes error” API? Is it that AbstractFloat and Rational are considered inherently lossy?

I think that’s exactly it. People working with floats will (if they know what they are doing) expect there to be some rounding involved. You don’t use == with floats, for instance.

There’s also the fact that integers have the rounding functions available, but you can’t, for instance, use round(Float64, x) to get the closest representable float.