Giter Site home page Giter Site logo

Comments (5)

waveform80 avatar waveform80 commented on August 24, 2024

I'm afraid any other language that implements 64-bit integers and 64-bit floats will indeed exhibit similar (though not necessarily precisely the same) behaviour. It ultimately depends how they handle casting for comparison operators...

The issue stems from the fact that (1<<53) + 1 evaluates to 9007199254740993. This has 16 (decimal) digits in it and fits happily in the range of a 64-bit integer. However, 64-bit floats only guarantee 15 digits of accuracy, and in this case converting the value to a float yields 9007199254740992. You can try adding one to that but obviously you'll just get the same value back (remember that it can't accurately represent that last digit so larger additions may work, but +1 won't).

We can demonstrate this with good old fashioned C:

#include <stdio.h>

int main(int argc, char *argv[]) {
    long long x = (1L << 53) + 1;

    printf("x = %lld\n", x);
    printf("(float)x = %f\n", (float)x);
    printf("x + 1.0 < x = %d\n", (long long)(x + 1.0) < x);

    return 0;
}

Note that the (long long) cast in the final printf is necessary to emulate Python's behaviour. Without that C coerces the right x operand to a float and the comparison returns negative (incorrectly because the right hand side of the comparison is indeed greater than the implicitly float coerced left).

Basically, Python's implicit casting behaviour is more correct here (though whether it's casting the float to a 64-bit int or casting both operands to something capable of accurately representing both like a Fraction or a Decimal instance, I don't know -- I'd hope the latter).

from pywat.

cosmologicon avatar cosmologicon commented on August 24, 2024

Sure, if you add an explicit cast to make C emulate Python's behavior, it'll give the same result. But if you use the implicit behavior (just put x + 1.0 < x), it won't. In my opinion, adding the explicit cast makes it clear enough what's going on, which is why I personally would not consider this a wat in C.

though whether it's casting the float to a 64-bit int or casting both operands to something capable of accurately representing both like a Fraction or a Decimal instance, I don't know -- I'd hope the latter

Based on what I remember from the Python source code, it's neither. When you compare a float to an int in Python, it doesn't convert them to a common type at all. There's special logic for this case to ensure an accurate result. I guess Ruby behaves the same way.

from pywat.

waveform80 avatar waveform80 commented on August 24, 2024

Hmm ... except in C, from one perspective you might convince yourself it's returning the wrong answer, and Python's returning the right one. It all depends on whether you accept the limitations of floating point types or not. I'll admit it's a bit of a convoluted argument, so I beg your indulgence with the following:

x = (1 << 53) + 1

At this point x is 9007199254740993 which is a fine value for a 64-bit integer (in Python or C).

x + 1.0 < x

Now ... we've explicitly specified we're adding a floating point so presumably we're expecting the LHS of this to be a floating point. However, due to the limitations of the floating point format, x is first converted to 9007199254740992.0 and adding 1.0 to it also returns 9007199254740992.0 (after all, if 9...3 converts to 9...2, then 9...2 + 1.0 must also result in 9...2).

So at this point in both Python and C we're comparing:

9007199254740992.0 < 9007199254740993

Python (and Ruby) do something (I haven't peeked under the covers to find out what yet) to ensure that it correctly returns True. C converts the RHS to a float (which naturally winds up being 9007199254740992.0 as above) and returns False (simply because x < x is False).

So, it's a "wat" in as much as intuitively x + 1 < x should always be False. But you're only getting the correct answer in C due to the operator being strictly less-than. Intuitively x + 1 <= x should always be False as well, but remove the cast in C and change the operator to "<=" and you'll get True back (because x <= x is True).

You will in Python too, but then that's the price of explicitly selecting a limited precision system like 64-bit floating point by writing + 1.0 instead of + 1 (which would stick with Python's "unlimited" integers). In other words, the "wat" stems from float's limited precision (specifically, the 53-bit mantissa) ... but that's not really Python's fault.

from pywat.

cosmologicon avatar cosmologicon commented on August 24, 2024

Oh, don't get me wrong. I definitely think Python gives the "right" answer, in that I wouldn't change it at all. I think that Python treats these numerical types very reasonably. I think the "price" here is well worth paying. The whole point of the wat is that even reasonable behavior can lead to surprising edge cases when you take them out of context.

Intuitively x + 1 <= x should always be False as well

Well, I tend to think that most people who have any familiarity with floating-point numbers will not be surprised that x + 1 == x is sometimes true. To me, that seems like an obvious side effect of finite precision. Just my humble opinion, though.

from pywat.

cosmologicon avatar cosmologicon commented on August 24, 2024

Changed the statement that this bug was initially about to also include Ruby. Thanks for the report!

from pywat.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.