Sign in or Join FriendFeed
FriendFeed is the easiest way to share online. Learn more »
Paul Buchheit
In Python, what is the value of this expression: x % 3.3 == (x+1) % 3.3
Unless it has a bug the answer is false - Dave Winer
False, I would expect, because no number is congruent to itself plus one mod 3.3, and Python modulo is sane with respect to negative numbers. You can't add 1 to a string, and only numbers and strings admit the % operator. Is there a trick? - ⓞnor
I cheated and ran it in the interactive interpreter. Its false for all numeric values of x I tried. Amazingly a string cannot be taken modulo 3.3. (Edit: I mean its a dynamic language after all, a string modulo 3.3 should skip every third letter or something equally clever but useless). - DGentry
Yes, there is a trick. - Paul Buchheit
I'll assume that the trick doesn't involve a user-defined class that defines __mod__, as that would be cheap. - Tudor Bosman
No, the solution is not a trick. This was an actual bug that I had in my code (don't cheat, Tudor). - Paul Buchheit
Is precedence the problem? - Daniel Dulitz
does it involve integer/long overflow? - Eric Kerr
There is no long overflow in Python (longs are arbitrarily large). I'm waiting for the answer to Daniel's question. - Tudor Bosman
It's True for certain values of x. I leave it to you to determine which values :) - Paul Buchheit
Paul, as you said "values of x", I'm assuming that this is not a precedence issue. That is, if I have def foo(x): return x % 3.3 == (x+1) % 3.3, then foo(x) will be True for some values of x. - Tudor Bosman
True for x = 1e+100 (insufficient precision to represent the +1). What do I win? - ⓞnor
True for 1e32 - Joe Beda
Ha ha, beat you. :) - ⓞnor
Heh -- by like 6 seconds. Real time, bitch. - Joe Beda
okay, now I have to look at the code to see what you were using large floats for :) - Tudor Bosman
Yeah, I'm wondering about the context. (Assuming this was the case you had in mind.) - ⓞnor
Yeah, somewhere around x=2**53 the loss of precision on the int to float conversion causes it to lose the +1 and the expression is True. - Paul Buchheit
Liked for the real time smackdown. Hi Joe! Long time no see. How's the family? We gotta get up to Seattle again soon to see all my friends there. - Robert Scoble
Pie - iTad
x was the hash() of a string, and at some point the values returned by hash() must have gotten a lot larger than when I had originally written the code. - Paul Buchheit
To me, nothing:-) - Francine Hardaway
You're taking hash values modulo 3.3? - ⓞnor
Hey Scoble -- definately -- I'd be happy to show you around the Google Seattle office. - Joe Beda
Wolfram|Alpha is never sure what to do with _my_ input. - Paul Buchheit
Wolfram|Alpha just hangs for me most of the time. - Joe Beda
If I have a counter 'i', then i % 3 == 0 will be True 1/3 of the time, but what if I want it to be True with some other arbitrary probability (such as 1/pi), but non-randomly? (so that the values are distributed as evenly as possible) This was my solution (except with > instead of ==). It's kind of overkill, but I couldn't resist the puzzle. - Paul Buchheit
I think a normal person would have done "hash(i) % 1000 < 318" or the like... but sure, it's cute that you do the modulo directly in floating point space. Cute until the gremlins of floating point *eat your brains*. There's a reason we stay away from that stuff! - ⓞnor
Okay - it gets stranger -- I wrote a binary search to find the inflection point. I didn't get what I expected. x=9007500000000000 -> True, x=9007500000000000+1 -> False, x=9007500000000000+51 -> True. There is something strange going on. Python version 2.5.4 (r254:67916, Apr 1 2009, 17:38:54) \n[GCC 4.0.1 (Apple Inc. build 5490)] - Joe Beda
Wolfram|Alpha also returns True around 2^53: http://www26.wolframalpha.com/input... - Karim
Dan, that solution would produce unnecessarily long sequences of zeros (or ones). Once I have that, I may as well just use random(). On the other hand, [int((i+1) % f > i % f) for i in range(0, 30)] will not produce any adjacent zeros if f is >= 2. - Paul Buchheit
You could use fixed point if you had a typed language and could select longs to hold the result, e.g if you want 3.3, then (counter * 10 + increment) % 33. Overflow bugs are insidious, these days languages should have support for arbitrary precision promotion. I'm reminded of Joshua Bloch's "Nearly All Binary Searches are Broken" blog post: http://googleresearch.blogspot.com/2006... - Ray Cromwell
Python already has arbitrarily large longs Ray (no integer overflow), so it should not be vulnerable to Joshua's binary search bug. I'm not sure what "counter" and "increment" are in your example though. - Paul Buchheit
Oh, I see, you want evenly interleaved values with the appropriate distribution? Then why were you using hash() at all? - ⓞnor
The hash() provides a starting position (hash(feed_id) + i). This is used by the crawl, and I don't want all the feeds having the same True/False values at the same time. The hash provides an even distribution across feeds, and the other part provides an even distribution across time. - Paul Buchheit
Paul, counter in your case would be hash(feed_id), and increment would be 'i' I'm guessing, the amount you want to add each time. The idea is, if you want to say, mimic x + 0.1 % 3.3, you instead use x * 10 + 1 % 33. Then, if you have arbitrary precision integers, you'll never overflow (the float mantissa/round-off error) - Ray Cromwell
Ray, the even easier solution was to use hash % 1000000 so that I'm nowhere near the floating point rounding error :). - Paul Buchheit
No objection there, keep it simple, and floats will be faster than arbitrary precision longs I suspect. :) - Ray Cromwell