Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Why is Float#to_s not returning what I'd expect?
>> 12345678901234566.0.to_s
=> "12345678901234566.0"
>> 12345678901234567.0.to_s
=> "12345678901234568.0"
>> 12345678901234568.0.to_s
=> "12345678901234568.0"
>> 12345678901234569.0.to_s
=> "12345678901234568.0"
>> 123456789012345678.0.to_s
=> "123456789012345680.0"

That's ... no good.

Which one of those do you think is an error?

12345678901234567.to_s(2).length == 54
Floats can only store 53 bits, so it its float equivalent is inexact.

jc00ke commented Dec 20, 2011


=> "12345678901234568.0"

but I guess my assumption is wrong. I understand the precision issue when they are actually floats, but as strings I would expect them to be a digit-for-digit copy as a string, that's all.

They can't be a digit-for-digit copy, as that requires way too much information!

Are you really expecting 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475.to_s to be over 200 characters long?

Ruby converts to string with the following algo: the most accurate of the simplest decimal expansion that uniquely maps to that float representation. I.e. you are guaranteed that it round trips any_float.to_s.to_f == any_float, it is unique, i.e. float_a.to_s == float_b.to_s if and only if float_a == float_b. It's simplest in that you can't remove a decimal of the string without changing the resulting float.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment