Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

following MRI's 'weird' to_int conversion #4984

Closed
kares opened this issue Jan 17, 2018 · 4 comments
Closed

following MRI's 'weird' to_int conversion #4984

kares opened this issue Jan 17, 2018 · 4 comments

Comments

@kares
Copy link
Member

kares commented Jan 17, 2018

its obviously there for compatibility, but does it make sense?

maybe JRuby doesn't need to follow blindly as this could be considered an MRI bug:

jruby-9.1.15.0 :008 > 10000000000000000000000.0.to_int
 => 10000000000000000000000 
jruby-9.1.15.0 :009 > 100000000000000000000000.0.to_int
 => 99999999999999991611392 
jruby-9.1.15.0 :010 > 100000000000000000000000.0.to_i
 => 99999999999999991611392
@chrisseaton
Copy link
Contributor

chrisseaton commented Jan 17, 2018

I'm not sure which bit you think is weird, so apologies if I am explaining something to you that you already understand.

A 64-bit floating point number cannot represent the number 100000000000000000000000.0 - it doesn't have enough bits to do that in the encoding system it uses. So it represents it as a less precise 99999999999999991611392.0 instead.

$ irb
irb(main):001:0> '%.5f' % 100000000000000000000000.0
=> "99999999999999991611392.00000"

When you call to_int, Ruby doesn't have any way to 'remember' that you originally asked for 100000000000000000000000.0, as Ruby has nowhere to store this information, and if it did it would require something like a BigDecimal stored with every Float, which would take up tons of space.

This is explained in this Ruby FAQ.

https://github.com/rdp/ruby_tutorials_core/wiki/ruby-talk-faq#floats_imprecise

And this other document as well.

https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

With that information in mind, I think the behaviour of to_int makes sense, and I don't see how it could really do anything else without Ruby using the much slower BigDecimal class for all floating point values, which would seriously limit performance.

What do you think it should do instead?

@enebo enebo added this to the Invalid or Duplicate milestone Jan 17, 2018
@enebo
Copy link
Member

enebo commented Jan 17, 2018

This issue just brought back the nightmares of my numerical analysis (singular) class at college. This is known and expected as well. Also notice that nearly all other languages which support this float->int have the same behavior:

system ~/work/jruby bytelist_love * 1508% python
Python 2.7.14 (default, Dec 11 2017, 14:52:53) 
[GCC 7.2.1 20170915 (Red Hat 7.2.1-2)] on linux2
>>> print int(100000000000000000000000.0)
99999999999999991611392

Base 2 representation of floats just don't quite line up with our base 10 expectations...

@enebo enebo closed this as completed Jan 17, 2018
@chrisseaton
Copy link
Contributor

@kares
Copy link
Member Author

kares commented Jan 18, 2018

Thanks Chris and Tom, guess its back-2-school for me than :)

For the record, as I was stuck elsewhere - did not pay much attention, when I run into this and somehow wrongly assumed 100000000000000000000000.0 to be still representable as a 64-bit double value.

As Chris confirmed (on IRC) detecting a float precision being lost isn't possible in general ...

Somehow expected a narrow case - that Ruby might handle a number growing too big (as with integers).
But than why would anyone add .0 to a large int if he expects exactness - so handling this narrow case seems pointless + there's 123r syntax. The linked recent discussion on MRI tracker seems interesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants