From: Brent Roman Date: 2009-03-03T16:41:18+09:00 Subject: [ruby-core:22638] Re: suggestions for float OK. I apologize in advance. Soapbox on... I, for one, like Ruby's current approach to numeric type conversions. There is an automatic promotion from Fixnum to Bignum to prevent overflow. (a nice feature borrowed from SmallTalk) However, as others have pointed out, there is no analogous promotion between discrete, countable Integer types and Floats. This is because all Floats are *approximations* of abstract, continuous Real numbers. Floats are imprecise by design. They are intended to represent measured quantities, not countable objects. Any real valued measurement is likely to have more error in its underlying physics than the 8-byte binary floating point format Ruby uses to approximate that value. Floats should not be used for counting *anything* discrete. Not pennies, not array elements, not machine states. (ok, maybe pennies if you are dealing with current stock prices :-) Sure, they can approximate 1.0 fairly well. But, 1.1 is an inexact repeating binary fraction. A variant of the float to string conversion that tries to preserve all the binary information would certainly be useful, but not as the default to_s method. That is, unless you think that: irb> 2.1 - 3.0 -0.8999999999999999 would not be "surprising"! (well, at least annoying) Then, of course, there remains the question of efficiency. Many simple iterative numerical algorithms will cause BigDecimal and Rational numbers to balloon in bytes required as they struggle to maintain perfect accuracy. And, as they become bigger in memory, they will also become slower. Think of numerical integration, for example, or most any sort of successive approximation, in general. But, theoretical niceties aside, most plain folks are surprised when their fancy computer says: 2.1 - 3.0 != -0.9 What would fix this problem while still preserving efficiency and keep us numerical nerds happy? One very elegant fix would be to invent a DecimalFloat type. It would have limited precision, as Floats do, but 0.1 would be represented precisely, as we finger counting humans expect it to be. I've never seen this implemented in any other language. It would be a cool experiment. What most numerical methods folks do in practice, is to define equality of floats over an epsilon interval that is context dependent. So, if you insist on counting dollars with Floats, any values equal to within 1/2 a penny (or 0.005 dollars) might be considered "equal" for all practical purposes. Still, it's a pain to have to specify the epsilon all the time. Here's one way to avoid that: require 'delegate' class Money < DelegateClass(Float) Epsilon = 0.005 def <=> other diff = self - other return -1 if diff > Epsilon return 1 if diff < -Epsilon 0 end def initialize dollars super dollars.to_f end end def Money euro Money.new euro end ==== And, here's a suboptimal way to monkey patch Float with a "dynamic" epsilon that should behave as plain folks expect in most contexts: class Float def <=> other epsilon = self * 1e-14 diff = self - other return -1 if diff > epsilon return 1 if diff < -epsilon 0 end def == other #because built-in Float#== bypasses <=> (self<=>other) == 0 end end Note however, that this "dynamic epsilon" can be overcome by accumulating round off errors over many calculations. But, by then, it's not as obvious as 2.1 - 3.0 != -0.9, so most folks don't notice. - brent Roger Pack wrote: > >>> There is public-domain C code that formats floating-point values as the >>> shortest string that parses back to the exact same value. The only >>> thing that needs to happen is to interface Ruby with that code. > > Is that code good enough or should we fix it at "x" digits? I'd > probably prefer the code that formats it as the shortest string > possible [?] > > ...(snip)... > > I think the surprising part of it for me is that we have a Fixnum -> > Bignum auto conversion "when a normal int would bite us" [like on > overflow] but do not have that same privilege with regard to the > floating point realm. No auto conversion. The bite remains. > > That being said, I think the fear is that BigDecimal will be so very > slow that it would be too much of a performance hit. As in probably > extremely slow. > > The question then is which of these two unsultry choices you'd > prefer....well for me I would prefer the one that makes me worry less, > which would be BigDecimal :) > > If the hit is deemed too hard though, I suppose the better formatting > at least helps us track down the bugs when they happen, if not avoid > them. > Thoughts? > -=r > > > -- View this message in context: http://www.nabble.com/-ruby-core%3A22325--suggestions-for-float-tp22144150p22303851.html Sent from the ruby-core mailing list archive at Nabble.com.