Skip to content
Create a gist now

Instantly share code, notes, and snippets.

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
Something went wrong with that request. Please try again.