a = 1333.3339999999964 b = 1333.3339999999965 c = 1333.334 puts a # 1333.334 puts b # 1333.334 puts c # 1333.334 puts a == b # => false puts a == c # => false puts b == c # => false ######################################################### # HELP ME^^ # # How can I see 'real value' of Float object(a, b, c) ? #########################################################

on 2008-12-17 03:39

on 2008-12-17 03:47

> # How can I see 'real value' of Float object(a, b, c) ? >> sprintf("%.3f", 1.6804985609845) => "1.680" >> sprintf("%.8f", 1.6804985609845) => "1.68049856" cheers, _c

on 2008-12-19 05:02

Kyung won Cheon wrote: > puts b == c # => false > > ######################################################### > # HELP ME^^ > # > # How can I see 'real value' of Float object(a, b, c) ? > ######################################################### Comparing floating point numbers is usually not a very good idea. They're only approximations of the real number you're trying to represent. For that reason, when printing floating point numbers, it's useful to specify with what precision you want to print them. This usually involves some sort of format string. The sprintf example works, but I prefer something like this. a = 6.232523 puts ("%.3f" % a)

on 2008-12-19 08:14

On Tue, Dec 16, 2008 at 8:32 PM, Kyung won Cheon <removed_email_address@domain.invalid> wrote: > ######################################################### > # HELP ME^^ http://docs.sun.com/source/806-3568/ncg_goldberg.html

on 2008-12-19 20:17

On Dec 19, 2008, at 1:05 AM, Gregory B. wrote: > On Tue, Dec 16, 2008 at 8:32 PM, Kyung won Cheon <removed_email_address@domain.invalid > > wrote: > >> ######################################################### >> # HELP ME^^ > > http://docs.sun.com/source/806-3568/ncg_goldberg.html That is the document I usually send people to also. I think the critical insight to understand is that floating point literals written in decimal notation can not be exactly represented internally as a binary value. Since there is no one-to-one correspondence between the two representations even the simplest expression can introduce rounding or approximation errors. The real number (1/10) has a finite decimal representation but an infinite binary representation so: puts 0.1 requires that the string '0.1' be converted to an approximate floating point representation of (1/10) and then that representation be converted back to decimal number for output. You get different results depending on how much precision you ask for in those conversions: >> (1..50).each { |p| puts "%0.*f" % [p, 0.1] } 0.1 0.10 0.100 0.1000 0.10000 0.100000 0.1000000 0.10000000 0.100000000 0.1000000000 0.10000000000 0.100000000000 0.1000000000000 0.10000000000000 0.100000000000000 0.1000000000000000 0.10000000000000001 0.100000000000000006 0.1000000000000000056 0.10000000000000000555 0.100000000000000005551 0.1000000000000000055511 0.10000000000000000555112 0.100000000000000005551115 0.1000000000000000055511151 0.10000000000000000555111512 0.100000000000000005551115123 0.1000000000000000055511151231 0.10000000000000000555111512313 0.100000000000000005551115123126 0.1000000000000000055511151231258 0.10000000000000000555111512312578 0.100000000000000005551115123125783 0.1000000000000000055511151231257827 0.10000000000000000555111512312578270 0.100000000000000005551115123125782702 0.1000000000000000055511151231257827021 0.10000000000000000555111512312578270212 0.100000000000000005551115123125782702118 0.1000000000000000055511151231257827021182 0.10000000000000000555111512312578270211816 0.100000000000000005551115123125782702118158 0.1000000000000000055511151231257827021181583 0.10000000000000000555111512312578270211815834 0.100000000000000005551115123125782702118158340 0.1000000000000000055511151231257827021181583405 0.10000000000000000555111512312578270211815834045 0.100000000000000005551115123125782702118158340454 0.1000000000000000055511151231257827021181583404541 0.10000000000000000555111512312578270211815834045410

on 2008-12-19 21:59

and just in case you need further convincing, this is the scariest example i've ever seen. taken from Stefano T.'s http://intervals.rubyforge.org/ Take into consideration the rather innocent looking function def f(x,y) (333.75-x**2)* y**6 + x**2 * (11* x**2 * y**2-121 * y**4 -2) + 5.5 * y**8 + x/(2*y) end We can calculate it for some specific x and y, f(77617.0,33096.0) # => 1.17260394005318 There is only one problem: this result is WRONG. The correct result can be obtained by calculating separately the numerator and denominator of f using integer arithmetic. def f_num(x,y) ((33375- 100 * x**2)* y**6 + 100 * x**2 * (11* x**2 * y**2-121 * y**4 -2) + 550 * y**8) * 2*y + 100 *x end def f_den(x,y) 200*y end f_num(77617, 33096).to_f / f_den(77617, 33096).to_f # => -0.827396059946821 _c

on 2008-12-20 13:37

I get the correct answer using bc too: $ bc scale=100 x=77617 y=33096 t1=(333.75-x*x)*y*y*y*y*y*y t2=x*x*(11*x*x*y*y - 121*y*y*y*y - 2) t3=5.5*y*y*y*y*y*y*y*y t4=x/(2*y) t1+t2+t3+t4 -.827396059946821368141165095479816291999033115784384819917814841672\ 7096930142615421803239062122310854 However, using BigDecimal, the answer is remarkably different: require "bigdecimal" puts f(BigDecimal.new("77167.0"),BigDecimal.new("33096.0")) # => 9.15359360631475e+34 That's a sign plus 35 orders of magnitude different :-)

on 2008-12-20 16:04

On Sat, Dec 20, 2008 at 5:29 AM, Brian C. <removed_email_address@domain.invalid> wrote: > However, using BigDecimal, the answer is remarkably different: > > require "bigdecimal" > puts f(BigDecimal.new("77167.0"),BigDecimal.new("33096.0")) > # => 9.15359360631475e+34 > > That's a sign plus 35 orders of magnitude different :-) When I use BigDecimal all the way through and keep things clean in terms of groupings (explicit parens around *everything*), I get what appears to be the correct answer: require 'bigdecimal' SCALE = 100 AAA = BigDecimal.new("333.75", SCALE) BBB = BigDecimal.new("11.0", SCALE) CCC = BigDecimal.new("121.0", SCALE) DDD = BigDecimal.new("2.0", SCALE) EEE = BigDecimal.new("5.5", SCALE) def fun(x,y) puts ( (AAA - (x**2)) * (y**6) ) + ( (x**2) * ((BBB * (x**2) * (y**2)) - (CCC * (y**4)) - DDD )) + ( EEE * (y**8) ) + ( x / (DDD * y) ) end fun(BigDecimal.new("77617.0", SCALE), BigDecimal.new("33096.0", SCALE)) Gives: -0.8273960599468213681411650954798162919990331157843848199178148416727096930142615421803239062122310853275320280396422528402224E0 Is there something I'm missing? Seems like it would be pretty safe to use BigDecimal in this case. -Michael

on 2008-12-20 18:11

You're right, it works if you explicitly promote some of the constants to BigDecimal: class Numeric def bd BigDecimal.new(to_s,100) end end def f(x,y) (333.75.bd-x**2)* y**6 + x**2 * (11 * x**2 * y**2-121 * y**4 - 2) + 5.5.bd * y**8 + x/(2*y) end puts f(77617.bd,33096.bd) I didn't change any parentheses, just added .bd at certain places. The trouble seems to be: mixing BigDecimal and Integer works fine (promotes to BigDecimal), but mixing BigDecimal with Float downgrades to Float. irb(main):007:0> BigDecimal.new("7",100) + 2 => #<BigDecimal:b7f07910,'0.9E1',4(12)> irb(main):008:0> 2 + BigDecimal.new("7",100) => #<BigDecimal:b7f02b68,'0.9E1',4(12)> irb(main):009:0> BigDecimal.new("7",100) + 2.0 => 9.0 irb(main):010:0> (BigDecimal.new("7",100) + 2.0).class => Float So you have to be careful not to mix any Float constants in.

on 2008-12-24 10:35

On Fri, 19 Dec 2008 14:51:29 -0500, Christophe M. wrote: > and just in case you need further convincing, this is the scariest > example i've ever seen. taken from Stefano T.'s > http://intervals.rubyforge.org/ The example you give is pretty scary, but there's much scarier. You don't need a big complicated function to hit weird floating point anomalies. x + y - y should always equal x, right? irb(main):012:0> 1.0 + 3.0 - 3.0 => 1.0 Seems to work. Except when it doesn't... irb(main):017:0> x = 1.0/3 => 0.333333333333333 irb(main):018:0> x + 0.1 - 0.1 == x => false > Take into consideration the rather innocent looking function > > def f(x,y) > (333.75-x**2)* y**6 + x**2 * (11* x**2 * y**2-121 * y**4 -2) + > 5.5 * y**8 + x/(2*y) > end You've obviously lived a depraved life if you think that looks innocent :-) > We can calculate it for some specific x and y, > > f(77617.0,33096.0) # => 1.17260394005318 > > There is only one problem: this result is WRONG. The correct result can > be obtained by calculating separately the numerator and denominator of f > using integer arithmetic. Out of curiosity, I tried this equation in Python, and got the same result. Hardly surprising, as Python and Ruby will probably be using the same floating point library. I also tried in on my HP-48GX calculator, and got the same result too. If arithmetic truths could be voted on, that would be three votes for the wrong answer :) Does anyone have access to Mathematica? What does it give? > f_num(77617, 33096).to_f / f_den(77617, 33096).to_f > # => -0.827396059946821 Just to add more confusion to the story, here's another mathematically equivalent expression (unless I've made a silly mistake): irb(main):026:0> def f2(x, y) irb(main):027:1> a = x**2 irb(main):028:1> b = y**2 irb(main):029:1> f = x/(2*y) irb(main):030:1> 11*a*b*(a - 11*b)+(333.75 - a)*b**3 + 5.5*b**4 - 2*a+f irb(main):031:1> end => nil irb(main):032:0> f2(77617, 33096) => -12048797377.0 The moral of the story? Floats are evil. They are just similar enough to the real numbers you learn about in school to fool you into thinking that they behave just like reals, but they don't.