[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

about Float

Kyung won Cheon

12/17/2008 1:32:00 AM

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) ?
#########################################################
--
Posted via http://www.ruby-....

9 Answers

Christophe Mckeon

12/17/2008 1:40:00 AM

0


> # 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

--
Posted via http://www.ruby-....

Michael Morin

12/19/2008 2:54:00 AM

0

Kyung won Cheon wrote:
> 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) ?
> #########################################################

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)

--
Michael Morin
Guide to Ruby
http://ruby....
Become an About.com Guide: beaguide.about.com
About.com is part of the New York Times Company

Gregory Brown

12/19/2008 6:06:00 AM

0

On Tue, Dec 16, 2008 at 8:32 PM, Kyung won Cheon <kdream95@gmerce.co.kr> wrote:

> #########################################################
> # HELP ME^^

http://docs.sun.com/source/806-3568/ncg_gol...

--
Technical Blaag at: http://blog.majesticseacr...
Non-tech stuff at: http://metametta.bl...
"Ruby Best Practices" Book now in O'Reilly Roughcuts:
http://rubybestpra...

Gary Wright

12/19/2008 6:09:00 PM

0


On Dec 19, 2008, at 1:05 AM, Gregory Brown wrote:

> On Tue, Dec 16, 2008 at 8:32 PM, Kyung won Cheon <kdream95@gmerce.co.kr
> > wrote:
>
>> #########################################################
>> # HELP ME^^
>
> http://docs.sun.com/source/806-3568/ncg_gol...

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





Christophe Mckeon

12/19/2008 7:51:00 PM

0

and just in case you need further convincing, this is the scariest
example i've ever seen. taken from Stefano Taschini's
http://intervals.ruby...

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
--
Posted via http://www.ruby-....

Brian Candler

12/20/2008 11:29:00 AM

0

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
-.8273960599468213681411650954798162919990331157843848199178148416727096930142615421803239062122310854

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 :-)
--
Posted via http://www.ruby-....

Michael Libby

12/20/2008 1:56:00 PM

0

On Sat, Dec 20, 2008 at 5:29 AM, Brian Candler <b.candler@pobox.com> 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



--
Michael C. Libby
www.mikelibby.com

Brian Candler

12/20/2008 4:03:00 PM

0

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.
--
Posted via http://www.ruby-....

Steven D'Aprano

12/24/2008 8:33:00 AM

0

On Fri, 19 Dec 2008 14:51:29 -0500, Christophe Mckeon wrote:

> and just in case you need further convincing, this is the scariest
> example i've ever seen. taken from Stefano Taschini's
> http://intervals.ruby...

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?


> 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


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.


--
Steven