About Float


#1

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) ?

#########################################################


#2

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


#3

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)


#4

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


#5

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


#6

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-x2)* y6 + x2 * (11* x2 * y2-121 * y4 -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 * x2)* y6 +
100 * x2 * (11* x2 * y2-121 * y4 -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


#7

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 :slight_smile:

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 - (x2)) * (y6) ) +
( (x2) * ((BBB * (x2) * (y2)) - (CCC * (y4)) - 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


#8

I get the correct answer using bc too:

$ bc
scale=100
x=77617
y=33096
t1=(333.75-xx)yyyyyy
t2=x
x*(11xxyy - 121yyyy - 2)
t3=5.5yyyyyyyy
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 :slight_smile:


#9

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-x2)* y6 + x2 * (11 * x2 * y2-121 * y4 - 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.


#10

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-x2)* y6 + x2 * (11* x2 * y2-121 * y4 -2) +
5.5 * y**8 + x/(2*y)
end

You’ve obviously lived a depraved life if you think that looks
innocent :slight_smile:

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 :slight_smile:

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 = x2
irb(main):028:1> b = y
2
irb(main):029:1> f = x/(2y)
irb(main):030:1> 11
ab(a - 11b)+(333.75 - a)b**3 + 5.5b**4 - 2a+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.