Embed URL


SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Why is Float#to_s not returning what I'd expect?

View ruby193-float_to_s_wtf.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14
>> 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.



=> "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.