From: Kent Dahl Date: 2001-07-29T22:29:43+09:00 Subject: [ruby-talk:18741] Re: Numbers classes.. Rational number? [was: Ruby as opposed to Python?] Kero van Gelder wrote: > 1 Dutch guilder is wordt 2.20something Euro. > > that's a float :) It looks like a float, but are you sure 2.20 can be represent accurately using a float, or is that an approximation? 2.20 == 2 + 1/5 Unfortunately, floating-point formats can't store fiths. Here the approximation doesn't pose a problem, but once you've got one hundre billion and a 1/5 dollars, you've got a problem. > I'd like Rationals in Ruby, but a few divisions can run into huge > BixNums for denominator and whatstheothercalled. That can be an > unexpected speed slowdown. Guess you'd get: > > 5 / 2 => Rational(5, 2) > 5.0 / 2 => Float(2.5) .... for some reason the Java touting "operator-overloading is evil" mantra springs to mind here :-) But even if I'd have to use some explisit verbose "divide" method, I think that it is worth adding. As for huge Bignums for denominator and divisor(or is it dividend?), perhaps one could do some normalization of the Rational? Ie, Rational(100,200) == Rational(1,2)? Some clever bitwise and-ing and shifting would probably do the trick. My take on it is this: A float is basically a rational. Or a subset of rational, since Rational can represent any number Float can, but not the other way. The only floatingpoint formats I've seen (up close) use something like: a * 2^b Which is basically a rational: (a * 2^b) == (a / 2^-b) The reason for most of the approximation losses of floats, is the range restrictions of a and b. (The tying to base 2 also has impact) After seeing the light that is Bignum, it seems naturally to also have a Bigfloat ( basically a float with a and b that can be Bignums) and a Rational ( where the divisor is any possible Bignum, and not a multiple of 2) > which raises the question: > > Rational(5, 2) / 3.0 => Rational? Float? (5/2) / (3/1) == (5/2) * (1/3) = (5*1/2*3) == (5/6) if my math skills don't fail me. In this case I would assume the Rational / operator did the honorable thing, and preserved as much information as possible, despite slowness. If I wanted a float, I would do: Rational(5,2).to_f / 3.0 Assuming that the internal data for the float (a and b) can be extracted, the Rational class has no problem dividing, multiplying or adding with a float, since it basically treats it like Rational. As for slowness, Float already seems somewhat plagued since its not an immediate value (but thats more a GC thing). However, I do strongly believe that accuracy and information preservation is more paramount than speed. I'd rather have the operators be slow and correct, and have some alternative, verbose and fast methods, doing the same but giving a rats behind about accuracy. .... While I'm ranting about numbers: Is there any plans to have "bang" versions of numeric operators? irb(main):077:0> a = b = 5.0 5.0 irb(main):078:0> irb(main):079:0* a *=2 10.0 irb(main):080:0> b 5.0 This seems to indicate that a*=b is just syntactic sugar for a=a+b, which is probably the element of least surprise, atleast when converting Java / C++ programmers more familiar with by-value semantics. But if I put my OO-purist cap on and start chanting, I feel like the *= operator violates the object-message paradigm: I would assume the object is changed inplace. So, how about mul!, div!, plus! and minus! to complement (and imitate for immediate types) the operators *=, /=, += and -= that yields this functionality: a = b = 5.0 #=> 5.0 a.mul! 2 #=> 10.0 b #=> 10.0 On numeric objects that are real (and bother the GC), I think this might help on efficiency, avoiding the creation of an object. The only real problem I see, is the confusion it could lead to when working with immediate values that _may_ turn into true objects due to a call: a = b = 5 #=> 5 a.mul! 2 #=> 10 b #=> 5 # immediate value, therefore not changed versus a = b = myLargeNumber # myLargeNumber could be Fixnum, Bignum, Float etc a.mul! 2 #=> myLargeNumber*2 b # Just what is b now? where b would be myLargeNumber if it was a Fixnum, but would be myLargeNumber*2 if it was a true object (Bignum, Float, etc) Have I gone completely mad, missed something obvious or? Comments? -- <[ Kent Dahl ]>================<[ http://www.stud.ntnu.no/~kentda/ ]> )____(stud.techn.;ind.�k.data)||(softwareDeveloper.at(Trustix))_( /"Opinions expressed are mine and not those of my Employer, "\ ( "the University, my girlfriend, stray cats, banana fruitflies, " ) \"nor the frontal lobe of my left cerebral hemisphere. "/