Weirdness: (-0.666667 + 0.333333)

Discussion in 'C++' started by Corne' Cornelius, May 5, 2004.

  1. Hi,

    I'm experiencing some weirdness in a program, when subtracting 2
    (double)'s which should result in 0, but instead it returns
    -1.11022e-16. It looks to me that changing the double x_step decleration
    to unsigned type, might help, but the compiler complains when i try that.

    Any ideas ?

    #include <iostream>
    using namespace std;

    int main(int argc, char *argv[]) {

    double x1 = -1;
    double x2 = 1;
    double nx = 6;
    int pos = 0;
    double x = 0.0;
    double x_step = 0.0;

    x_step = (x2 - x1) / nx;

    x = x1;
    for (pos = 0; pos < nx; pos++) {
    cout << x << " +\t" << x_step << " =\t " << (x +
    x_step) << endl;
    x = x + x_step;
    }

    return 0;
    }


    Output:

    -1 + 0.333333 = -0.666667
    -0.666667 + 0.333333 = -0.333333
    -0.333333 + 0.333333 = -1.11022e-16
    -1.11022e-16 + 0.333333 = 0.333333
    0.333333 + 0.333333 = 0.666667
    0.666667 + 0.333333 = 1
     
    Corne' Cornelius, May 5, 2004
    #1
    1. Advertising

  2. Corne' Cornelius

    bartek Guest

    Corne' Cornelius <> wrote in
    news:p:

    > Hi,
    >
    > I'm experiencing some weirdness in a program, when subtracting 2
    > (double)'s which should result in 0, but instead it returns
    > -1.11022e-16. It looks to me that changing the double x_step decleration
    > to unsigned type, might help, but the compiler complains when i try that.
    >
    > Any ideas ?


    That's the nature of floating point arithmetic. You shouldn't compare
    against exact values, beacause of rounding errors (which are unavoidable,
    though usually very small).

    You should check against some small epsilon range instead of comparing
    exact numbers.

    --
    :: bartekd [at] o2 [dot] pl
     
    bartek, May 5, 2004
    #2
    1. Advertising

  3. Corne' Cornelius

    Bill Seurer Guest

    Corne' Cornelius wrote:

    > I'm experiencing some weirdness in a program, when subtracting 2
    > (double)'s which should result in 0, but instead it returns
    > -1.11022e-16.


    Doubles do not always exactly represent the value of a number but are an
    approximation of the value. This is especially true for computed values.

    See http://docs.sun.com/source/806-3568/ncg_goldberg.html
     
    Bill Seurer, May 5, 2004
    #3
  4. I've rounded the x_step var to a couple of places after the decimal
    point which seem to help, i need a number closer to 0 then what the
    overflow results in.

    Thanks !



    bartek wrote:
    > Corne' Cornelius <> wrote in
    > news:p:
    >
    >
    >>Hi,
    >>
    >>I'm experiencing some weirdness in a program, when subtracting 2
    >>(double)'s which should result in 0, but instead it returns
    >>-1.11022e-16. It looks to me that changing the double x_step decleration
    >>to unsigned type, might help, but the compiler complains when i try that.
    >>
    >>Any ideas ?

    >
    >
    > That's the nature of floating point arithmetic. You shouldn't compare
    > against exact values, beacause of rounding errors (which are unavoidable,
    > though usually very small).
    >
    > You should check against some small epsilon range instead of comparing
    > exact numbers.
    >
     
    Corne' Cornelius, May 5, 2004
    #4
  5. Corne' Cornelius

    bartek Guest

    Corne' Cornelius <> wrote in
    news::

    > I've rounded the x_step var to a couple of places after the decimal
    > point which seem to help, i need a number closer to 0 then what the
    > overflow results in.


    first...

    #include <limits>

    ....then...

    std::numeric_limits<double>::epsilon()

    ....will give you the smallest possible increment from 1.
    Unfortunately rounding errors can be bigger than that.
    It all depends on what you're actually doing. You should choose the
    threshold based on that.
    --
    :: bartekd [at] o2 [dot] pl
     
    bartek, May 5, 2004
    #5
  6. Corne' Cornelius

    bartek Guest

    bartek <> wrote in
    news:Xns94E0A0C65D9D1bartekdqwertyuiopo2p@153.19.251.200:

    > Corne' Cornelius <> wrote in
    > news::
    >
    >> I've rounded the x_step var to a couple of places after the decimal
    >> point which seem to help, i need a number closer to 0 then what the
    >> overflow results in.

    >
    > first...
    >
    > #include <limits>
    >
    > ...then...
    >
    > std::numeric_limits<double>::epsilon()
    >
    > ...will give you the smallest possible increment from 1.
    > Unfortunately rounding errors can be bigger than that.
    > It all depends on what you're actually doing. You should choose the
    > threshold based on that.


    I mean -- based on what you're doing, not on numeric_limits::epsilon()
    that is.

    --
    :: bartekd [at] o2 [dot] pl
     
    bartek, May 5, 2004
    #6
  7. Corne' Cornelius

    Chris Dams Guest

    Hi!

    Corne' Cornelius <> writes:

    >I'm experiencing some weirdness in a program, when subtracting 2
    >(double)'s which should result in 0, but instead it returns
    >-1.11022e-16. It looks to me that changing the double x_step decleration
    >to unsigned type, might help, but the compiler complains when i try that.


    The problem is that real numbers on a computer have limited accuracy.
    Results of substracting two real numbers that are (almost) equal, should
    not be trusted. Solutions to this problem generally depend on what
    exactly you want to do.

    Bye,
    Chris Dams
     
    Chris Dams, May 5, 2004
    #7
  8. Corne' Cornelius

    Pete Becker Guest

    Bill Seurer wrote:
    >
    > Doubles do not always exactly represent the value of a number but are an
    > approximation of the value. This is especially true for computed values.
    >


    Doubles exactly represent the value that they hold. They sometimes don't
    hold the result that you would get from some computation with infinite
    precision arithemetic. But, then, neither do ints. In their first week
    future programmers learn to accept that (1/3)*3 isn't 1. For some reason
    <g> it's harder for them to accept that with floating point values.

    --

    Pete Becker
    Dinkumware, Ltd. (http://www.dinkumware.com)
     
    Pete Becker, May 6, 2004
    #8
  9. Corne' Cornelius wrote:

    > Hi,
    >
    > I'm experiencing some weirdness in a program, when subtracting 2
    > (double)'s which should result in 0, but instead it returns
    > -1.11022e-16. It looks to me that changing the double x_step decleration
    > to unsigned type, might help, but the compiler complains when i try that.
    >
    > Any ideas ?


    Don't compare two floating point numbers as such. Use the trick of an
    epsilon interval by Knuth (implemented in the fcmp package available at
    sourceforge.net) described in TAOCP Vol 2 Seminumerical algorithms.


    bye,
    gert
     
    Gert Van den Eynde, May 6, 2004
    #9
  10. i should've made it more clear what i actually want to do.

    I'm not really trying to compare 2 double which could be in accurate
    becuase of rounding errors.

    I'm writing a program that draws graphs on a cartesian plane, so in
    order to go on the x-axis from say -2, to +2, in 20 intervals, i need
    one of these point to be zero or very close to it.

    how could i make sure i don't get rounding problems ?


    Corne' Cornelius wrote:
    > Hi,
    >
    > I'm experiencing some weirdness in a program, when subtracting 2
    > (double)'s which should result in 0, but instead it returns
    > -1.11022e-16. It looks to me that changing the double x_step decleration
    > to unsigned type, might help, but the compiler complains when i try that.
    >
    > Any ideas ?
    >
    > #include <iostream>
    > using namespace std;
    >
    > int main(int argc, char *argv[]) {
    >
    > double x1 = -1;
    > double x2 = 1;
    > double nx = 6;
    > int pos = 0;
    > double x = 0.0;
    > double x_step = 0.0;
    >
    > x_step = (x2 - x1) / nx;
    >
    > x = x1;
    > for (pos = 0; pos < nx; pos++) {
    > cout << x << " +\t" << x_step << " =\t " << (x +
    > x_step) << endl;
    > x = x + x_step;
    > }
    >
    > return 0;
    > }
    >
    >
    > Output:
    >
    > -1 + 0.333333 = -0.666667
    > -0.666667 + 0.333333 = -0.333333
    > -0.333333 + 0.333333 = -1.11022e-16
    > -1.11022e-16 + 0.333333 = 0.333333
    > 0.333333 + 0.333333 = 0.666667
    > 0.666667 + 0.333333 = 1
    >
     
    Corne' Cornelius, May 6, 2004
    #10
  11. Corne' Cornelius wrote:

    > i should've made it more clear what i actually want to do.
    >
    > I'm not really trying to compare 2 double which could be in accurate
    > becuase of rounding errors.
    >
    > I'm writing a program that draws graphs on a cartesian plane, so in
    > order to go on the x-axis from say -2, to +2, in 20 intervals, i need
    > one of these point to be zero or very close to it.
    >
    > how could i make sure i don't get rounding problems ?
    >

    You can't. The only thing you can do is to compare your value of x to zero
    (using fcmp) and if it's close enough force it to be zero. Btw, Is the
    difference between 1e-16 and 0.0 so significant that it will show up on a
    graph in the range [-1,1] ?

    bye,
    gert
     
    Gert Van den Eynde, May 6, 2004
    #11
  12. heh, i also thaught of not worrying about it being 1e-16, but then
    there's a pixel missing where x is 0.

    Looks like i will have to make 2 loops and 1 statement.

    for when:
    x - epsilon() < 0
    x = 0
    x + epsilon() > 0

    Gert Van den Eynde wrote:
    > Corne' Cornelius wrote:
    >
    >
    >>i should've made it more clear what i actually want to do.
    >>
    >>I'm not really trying to compare 2 double which could be in accurate
    >>becuase of rounding errors.
    >>
    >>I'm writing a program that draws graphs on a cartesian plane, so in
    >>order to go on the x-axis from say -2, to +2, in 20 intervals, i need
    >>one of these point to be zero or very close to it.
    >>
    >>how could i make sure i don't get rounding problems ?
    >>

    >
    > You can't. The only thing you can do is to compare your value of x to zero
    > (using fcmp) and if it's close enough force it to be zero. Btw, Is the
    > difference between 1e-16 and 0.0 so significant that it will show up on a
    > graph in the range [-1,1] ?
    >
    > bye,
    > gert
     
    Corne' Cornelius, May 6, 2004
    #12
  13. Corne' Cornelius wrote:
    >
    > heh, i also thaught of not worrying about it being 1e-16, but then
    > there's a pixel missing where x is 0.


    Then your transformation from world coordinates to
    pixel coordinates is in error, if such a small deviation
    from 0 makes that effect.

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, May 6, 2004
    #13
  14. Karl Heinz Buchegger wrote:
    >
    > Corne' Cornelius wrote:
    > >
    > > heh, i also thaught of not worrying about it being 1e-16, but then
    > > there's a pixel missing where x is 0.

    >
    > Then your transformation from world coordinates to
    > pixel coordinates is in error, if such a small deviation
    > from 0 makes that effect.


    The usual error is to truncate instead of round when chopping
    of the fractional part in pixel space.

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, May 6, 2004
    #14
  15. Corne' Cornelius

    Chris Dams Guest

    Hi!

    Corne' Cornelius <> writes:

    >heh, i also thaught of not worrying about it being 1e-16, but then
    >there's a pixel missing where x is 0.


    If you want to draw a point for every pixels you should loop over pixels
    and not over doubles. On the other hand, making small steps and drawing
    a straight line between these, is likely to be good enough. Furthermore,
    if you draw points for every pixel in the x-direction you should also
    worry about what happens if the slope of your graph is bigger than 1.

    Bye,
    Chris Dams
     
    Chris Dams, May 6, 2004
    #15
  16. In message <>, Corne' Cornelius
    <> writes
    >i should've made it more clear what i actually want to do.
    >
    >I'm not really trying to compare 2 double which could be in accurate
    >becuase of rounding errors.
    >
    >I'm writing a program that draws graphs on a cartesian plane, so in
    >order to go on the x-axis from say -2, to +2, in 20 intervals, i need
    >one of these point to be zero or very close to it.
    >
    >how could i make sure i don't get rounding problems ?
    >


    You can often improve matters by using an integer loop counter:

    instead of: for (double x=xstart; x<xend; x+=step) {...}

    use something like: for (int i=istart; i<iend; ++i) { double x=i*xstep;
    ....}

    It doesn't get rid of the rounding errors, but it does ensure that they
    don't accumulate as you progress through the loop.
    --
    Richard Herring
     
    Richard Herring, May 7, 2004
    #16
    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. Wayne Myers

    POK Flag Weirdness wth binary files

    Wayne Myers, May 26, 2004, in forum: Perl
    Replies:
    1
    Views:
    476
    ! aaa
    May 27, 2004
  2. Replies:
    4
    Views:
    711
    J├╝rgen Exner
    Dec 7, 2004
  3. John Saunders
    Replies:
    4
    Views:
    3,547
    John Saunders
    Aug 29, 2003
  4. Chris Porter

    timezone / culture weirdness

    Chris Porter, Oct 24, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    348
    Bret Mulvey [MS]
    Oct 25, 2003
  5. steve
    Replies:
    4
    Views:
    535
    Brian van den Broek
    Mar 13, 2005
Loading...

Share This Page