About Float

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-forum.com/.

# 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-forum.com/\.

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

Become an About.com Guide: beaguide.about.com
About.com is part of the New York Times Company

http://docs.sun.com/source/806-3568/ncg_goldberg.html

···

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

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

--
Technical Blaag at: http://blog.majesticseacreature.com
Non-tech stuff at: http://metametta.blogspot.com
"Ruby Best Practices" Book now in O'Reilly Roughcuts:
http://rubybestpractices.com

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

and just in case you need further convincing, this is the scariest
example i've ever seen. taken from Stefano Taschini'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

···

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

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

···

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

and just in case you need further convincing, this is the scariest
example i've ever seen. taken from Stefano Taschini'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 :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?

  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.

···

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

--
Steven

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

--
Michael C. Libby
www.mikelibby.com

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-forum.com/.