floating point subtraction question

Discussion in 'Ruby' started by Nicholas Rahn, Nov 27, 2005.

  1. Hi,

    I'm a bit confused with some simple floating point arithmetic:

    % ruby -e 'puts "#{(1.2 - 1.0) == 0.2}"'
    false

    % ruby -e 'puts "#{(1.5 - 1.0) == 0.5}"'
    true

    I'm sure there's a perfectly logical reason for this, but i think i've
    been staring at it for too long to see what it is.

    Can anyone shed some light on this?

    Thanks for your help,
    Nick

    ps:
    % ruby -v
    ruby 1.8.3 (2005-06-23) [i486-linux]
     
    Nicholas Rahn, Nov 27, 2005
    #1
    1. Advertising

  2. On Nov 27, 2005, at 3:41 PM, Nicholas Rahn wrote:
    > I'm a bit confused with some simple floating point arithmetic:
    >
    > % ruby -e 'puts "#{(1.2 - 1.0) == 0.2}"'
    > false
    >
    > % ruby -e 'puts "#{(1.5 - 1.0) == 0.5}"'
    > true


    Slim:~ gavinkistner$ irb
    irb(main):001:0> 1.2-1.0
    => 0.2
    irb(main):002:0> (1.2-1.0)==0.2
    => false
    irb(main):003:0> "%.31f" % [1.2-1.0]
    => "0.1999999999999999555910790149937"
    irb(main):004:0> "%.31f" % [0.2]
    => "0.2000000000000000111022302462516"
    irb(main):005:0> "%.31f" % [1.2]
    => "1.1999999999999999555910790149937"

    Because many digits cannot be precisely represented as powers of 2.

    For more info, try a plethora of online resources on floating point
    math, such as:
    http://en.wikipedia.org/wiki/Floating_point#Problems_with_floating-point
     
    Gavin Kistner, Nov 27, 2005
    #2
    1. Advertising

  3. Nicholas Rahn

    Guest

    On Nov 27, 2005, at 5:41 PM, Nicholas Rahn wrote:
    > I'm a bit confused with some simple floating point arithmetic:
    >
    > % ruby -e 'puts "#{(1.2 - 1.0) == 0.2}"'
    > false
    >
    > % ruby -e 'puts "#{(1.5 - 1.0) == 0.5}"'
    > true
    >
    > I'm sure there's a perfectly logical reason for this, but i think i've
    > been staring at it for too long to see what it is.


    The short answer is that decimal floating point literals can not
    accurately represent the binary floating point values so you get
    all sorts of rounding errors. Take a look at
    http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html

    In general it is a mistake to use == to compare floating point values
    because
    of this mismatch. An alternate approach is to ask if the difference
    between two values is less than some small delta:

    instead of a == b
    use abs(a - b) < delta
    for some suitable (small, near zero) value of delta

    For all the gory details read "What Every Computer Scientist Should
    Know About Floating-Point"
    http://docs.sun.com/source/806-3568/ncg_goldberg.html
     
    , Nov 27, 2005
    #3
  4. Nicholas Rahn wrote:
    > Hi,
    >
    > I'm a bit confused with some simple floating point arithmetic:
    >
    > % ruby -e 'puts "#{(1.2 - 1.0) == 0.2}"'
    > false
    >
    > % ruby -e 'puts "#{(1.5 - 1.0) == 0.5}"'
    > true
    >
    > I'm sure there's a perfectly logical reason for this, but i think i've
    > been staring at it for too long to see what it is.
    >
    > Can anyone shed some light on this?
    >
    > Thanks for your help,
    > Nick
    >
    > ps:
    > % ruby -v
    > ruby 1.8.3 (2005-06-23) [i486-linux]


    This has nothing to do with Ruby, itself, but is a basic characteristic
    of nearly all languages and nearly all computers.

    Remember how you can't make 1/3 a decimal fraction, because it's
    0.3333333333333 -- carried out to infinity, so that if you add 1/3 + 1/3
    + 1/3, you get 0.9999999 -- carried out to infinity, instead of 1.0?
    Well, computers (almost always) use binary fractions, and you can't make
    1/10 a binary fraction, because it comes out as 0.000110011001100110011
    -- carried out to infinity, and so you get the same kind of problem.

    If you are doing science or engineering, it doesn't matter, because
    things in the real world don't come out as neat decimal fractions,
    anyway. But you do want to avoid checking for equality. Instead of

    x==y

    look for

    abs(x-y)<epsilon

    where epsilon is some really small number that serves for your purposes
    as "practically equal".

    If, on the other hand, you are working with money, don't use fractions.
    Calculate in cents (or centimes, or new pence, or whatever), and only
    divide by 100 (or whatever) at the last moment, when you're printing
    your results.

    (IBM mainframes have hardware to handle decimal fractions directly, and
    a very few languages -- COBOL, RPG, PL/I, and Ada '95 come to mind --
    have the extra features to make use of it. Some other languages, Java,
    for example, include libraries to help you do the "calculate in cents"
    trick. Ruby, however, does not at present include either facility.)

    --
    John W. Kennedy
    "But now is a new thing which is very old--
    that the rich make themselves richer and not poorer,
    which is the true Gospel, for the poor's sake."
    -- Charles Williams. "Judgement at Chelmsford"
     
    John W. Kennedy, Nov 27, 2005
    #4
  5. John W. Kennedy wrote:
    > Nicholas Rahn wrote:
    > > Hi,
    > >
    > > I'm a bit confused with some simple floating point arithmetic:
    > >
    > > % ruby -e 'puts "#{(1.2 - 1.0) == 0.2}"'
    > > false
    > >
    > > % ruby -e 'puts "#{(1.5 - 1.0) == 0.5}"'
    > > true
    > >
    > > I'm sure there's a perfectly logical reason for this, but i think i've
    > > been staring at it for too long to see what it is.
    > >
    > > Can anyone shed some light on this?
    > >
    > > Thanks for your help,
    > > Nick
    > >
    > > ps:
    > > % ruby -v
    > > ruby 1.8.3 (2005-06-23) [i486-linux]

    >
    > This has nothing to do with Ruby, itself, but is a basic characteristic
    > of nearly all languages and nearly all computers.
    >
    > Remember how you can't make 1/3 a decimal fraction, because it's
    > 0.3333333333333 -- carried out to infinity, so that if you add 1/3 + 1/3
    > + 1/3, you get 0.9999999 -- carried out to infinity, instead of 1.0?
    > Well, computers (almost always) use binary fractions, and you can't make
    > 1/10 a binary fraction, because it comes out as 0.000110011001100110011
    > -- carried out to infinity, and so you get the same kind of problem.
    >
    > If you are doing science or engineering, it doesn't matter, because
    > things in the real world don't come out as neat decimal fractions,
    > anyway. But you do want to avoid checking for equality. Instead of
    >
    > x==y
    >
    > look for
    >
    > abs(x-y)<epsilon
    >
    > where epsilon is some really small number that serves for your purposes
    > as "practically equal".
    >


    > (IBM mainframes have hardware to handle decimal fractions directly, and
    > a very few languages -- COBOL, RPG, PL/I, and Ada '95 come to mind --
    > have the extra features to make use of it. Some other languages, Java,
    > for example, include libraries to help you do the "calculate in cents"
    > trick. Ruby, however, does not at present include either facility.)


    BASIC on the 8-bit Atari used binary-coded decimal.
     
    William James, Nov 27, 2005
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    17
    Views:
    851
    CBFalconer
    Oct 27, 2007
  2. Keflavich
    Replies:
    13
    Views:
    705
    J. Robertson
    Dec 14, 2007
  3. Saraswati lakki
    Replies:
    0
    Views:
    1,372
    Saraswati lakki
    Jan 6, 2012
  4. teeshift
    Replies:
    2
    Views:
    274
    Chris Pearl
    Dec 1, 2006
  5. Jaroslav Dobrek

    subtraction of floating point numbers

    Jaroslav Dobrek, Feb 24, 2012, in forum: Python
    Replies:
    2
    Views:
    202
    Chris Rebert
    Feb 24, 2012
Loading...

Share This Page