Comments (5)
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.
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.
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.
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.
Changed the statement that this bug was initially about to also include Ruby. Thanks for the report!
from pywat.
Related Issues (20)
- The undocumented converse implication operator wat is not a wat HOT 6
- Other wats suggestions HOT 4
- All NaNs are unequal, but some are more unequal than others HOT 2
- Iterable types in comparisons HOT 6
- Translate to pt-br HOT 2
- "Fun with iterators" section is not a WAT HOT 1
- Indexing with floats - not really an index
- Scope
- "It just happens to work out that the truth table is the same as for the converse implication operator."
- Don't be stupid - read the docs
- Question 2
- while - else HOT 1
- Issue reference for containment test chaining
- Simpler imaginary nan-wat
- fun with mappings
- Question 5: zero sum is "possible" ? HOT 3
- Turn this into an interactive quiz?
- add wat: print not equal to lambda x: print(x) HOT 1
- Classmethod
- Minor: 0^0 is not 0 (mathematically) - explanation.md
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pywat.