round() wrong in Python 2.4?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Nils Grimsmo

    #1

    round() wrong in Python 2.4?

    Why did round() change in Python 2.4?

    $ python2.3
    Python 2.3.5 (#2, Jun 19 2005, 13:28:00)
    [GCC 3.3.6 (Debian 1:3.3.6-6)] on linux2[color=blue][color=green][color=darkred]
    >>> round(0.0225, 3)[/color][/color][/color]
    0.023[color=blue][color=green][color=darkred]
    >>> "%.3f" % round(0.0225, 3)[/color][/color][/color]
    '0.023'[color=blue][color=green][color=darkred]
    >>>[/color][/color][/color]
    $ python2.4
    Python 2.4.1 (#2, Jul 12 2005, 09:22:25)
    [GCC 4.0.1 (Debian 4.0.1-1)] on linux2[color=blue][color=green][color=darkred]
    >>> round(0.0225, 3)[/color][/color][/color]
    0.0219999999999 99999[color=blue][color=green][color=darkred]
    >>> "%.3f" % round(0.0225, 3)[/color][/color][/color]
    '0.022'[color=blue][color=green][color=darkred]
    >>>[/color][/color][/color]

    (Is this due to the different GCC used?)

    How do you correctly output floating-point numbers in 2.4?

    I do not like the "print number + EPS" solution, as you would need
    different EPS for different exponent sizes. In C you could get it by
    taking integer 1, and &-ing in the right exponent, and then casting to
    double via void*. This would not be very portable, though.


    Klem fra Nils

  • Jeremy Sanders

    #2
    Re: round() wrong in Python 2.4?

    Nils Grimsmo wrote:
    [color=blue]
    > Why did round() change in Python 2.4?[/color]

    It the usual floating point representation problem. 0.0225 cannot be
    represented exactly:

    xpc20:~> python
    Python 2.3.4 (#1, Mar 14 2005, 16:47:22)
    [GCC 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)] on linux2
    Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
    >>> 0.0225[/color][/color][/color]
    0.0224999999999 99999

    See


    If you need exact maths, then you're better off using integers or decimal
    arithmetic.

    Jeremy

    --
    Jeremy Sanders

    Comment

    • Robert Kern

      #3
      Re: round() wrong in Python 2.4?

      Jeremy Sanders wrote:[color=blue]
      > Nils Grimsmo wrote:
      >[color=green]
      >>Why did round() change in Python 2.4?[/color]
      >
      > It the usual floating point representation problem. 0.0225 cannot be
      > represented exactly:[/color]

      That's not what he's asking about. He's asking why his Python 2.3 rounds
      0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's
      the change in behavior that he's concerned with and isn't just the usual
      floating point problem.

      I'm going to suggest that it's a platform issue, possibly the change in
      compiler. I get identical results on OS X with both versions of Python
      both compiled by gcc-3.3 .

      [~]$ python2.3
      Python 2.3.5 (#1, Mar 20 2005, 20:38:20)
      [GCC 3.3 20030304 (Apple Computer, Inc. build 1809)] on darwin
      Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
      >>> 0.0225[/color][/color][/color]
      0.0224999999999 99999[color=blue][color=green][color=darkred]
      >>> round(0.0225, 3)[/color][/color][/color]
      0.023[color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]
      [~]$ python2.4
      Python 2.4.1 (#2, Mar 31 2005, 00:05:10)
      [GCC 3.3 20030304 (Apple Computer, Inc. build 1666)] on darwin
      Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
      >>> 0.0225[/color][/color][/color]
      0.0224999999999 99999[color=blue][color=green][color=darkred]
      >>> round(0.0225, 3)[/color][/color][/color]
      0.023[color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]

      --
      Robert Kern
      rkern@ucsd.edu

      "In the fields of hell where the grass grows high
      Are the graves of dreams allowed to die."
      -- Richard Harter

      Comment

      • Sion Arrowsmith

        #4
        Re: round() wrong in Python 2.4?

        Nils Grimsmo <nils.grimsmo@g mail.com> wrote:[color=blue]
        >Why did round() change in Python 2.4?
        >
        >$ python2.3
        >Python 2.3.5 (#2, Jun 19 2005, 13:28:00)
        >[GCC 3.3.6 (Debian 1:3.3.6-6)] on linux2[color=green][color=darkred]
        >>>> round(0.0225, 3)[/color][/color]
        >0.023[color=green][color=darkred]
        >>>> "%.3f" % round(0.0225, 3)[/color][/color]
        >'0.023'[color=green][color=darkred]
        >>>>[/color][/color]
        >$ python2.4
        >Python 2.4.1 (#2, Jul 12 2005, 09:22:25)
        >[GCC 4.0.1 (Debian 4.0.1-1)] on linux2[color=green][color=darkred]
        >>>> round(0.0225, 3)[/color][/color]
        >0.021999999999 999999[color=green][color=darkred]
        >>>> "%.3f" % round(0.0225, 3)[/color][/color]
        >'0.022'[color=green][color=darkred]
        >>>>[/color][/color]
        >
        >(Is this due to the different GCC used?)[/color]

        That would look like a good guess to me:

        $ python
        Python 2.4.1 (#2, May 5 2005, 11:32:06)
        [GCC 3.3.5 (Debian 1:3.3.5-12)] on linux2
        Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
        >>> round(0.0225, 3)[/color][/color][/color]
        0.023[color=blue][color=green][color=darkred]
        >>> "%.3f" % round(0.0225, 3)[/color][/color][/color]
        '0.023'[color=blue][color=green][color=darkred]
        >>>[/color][/color][/color]

        Is that python2.4 of yours from the python2.4 package or one
        you compiled up yourself?

        --
        \S -- siona@chiark.gr eenend.org.uk -- http://www.chaos.org.uk/~sion/
        ___ | "Frankly I have no feelings towards penguins one way or the other"
        \X/ | -- Arthur C. Clarke
        her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump

        Comment

        • Nils Grimsmo

          #5
          Re: round() wrong in Python 2.4?

          I am running Debian unstable for 386. Python 2.4 is from the official
          package archive, and seems to be compiled with GCC 4.0.2.

          $ dpkg -l python2.4
          ii python2.4 2.4.1-4 ...

          $ python2.4
          Python 2.4.1+ (#2, Sep 4 2005, 21:58:51)
          [GCC 4.0.2 20050821 (prerelease) (Debian 4.0.1-6)] on linux2
          Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
          >>>[/color][/color][/color]

          $ gcc-4.0 --version
          gcc-4.0 (GCC) 4.0.2 20050725 (prerelease) (Debian 4.0.1-3)


          Klem fra Nils

          Comment

          • Jeremy Sanders

            #6
            Re: round() wrong in Python 2.4?

            Robert Kern wrote:
            [color=blue]
            > That's not what he's asking about. He's asking why his Python 2.3 rounds
            > 0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's
            > the change in behavior that he's concerned with and isn't just the usual
            > floating point problem.[/color]

            You can't rely on either being true, given the nature of the inexact
            representation of the number, and the fact that python ignores quite a lot
            of the IEEE stuff. Different optimisations (particularly with the 80 bit
            floating point registers in x86), will lead to different represenations.
            Any code which relies on a particular behaviour is broken.

            Jeremy

            --
            Jeremy Sanders

            Comment

            • Antoon Pardon

              #7
              Re: round() wrong in Python 2.4?

              Op 2005-09-13, Robert Kern schreef <rkern@ucsd.edu >:[color=blue]
              > Jeremy Sanders wrote:[color=green]
              >> Nils Grimsmo wrote:
              >>[color=darkred]
              >>>Why did round() change in Python 2.4?[/color]
              >>
              >> It the usual floating point representation problem. 0.0225 cannot be
              >> represented exactly:[/color]
              >
              > That's not what he's asking about. He's asking why his Python 2.3 rounds
              > 0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's
              > the change in behavior that he's concerned with and isn't just the usual
              > floating point problem.[/color]

              I would say the usual floating point problem is involved.

              Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down.

              0.0225 isn't representable and it happens that the actual number
              you get differ. Now which number python should choose when it is
              fed 0.0225, I don't know. But expressing the different behaviour
              as a change in round, suggest that the O.P. would be wise to
              learn about floating point problems

              --
              Antoon Pardon

              Comment

              • Robert Kern

                #8
                Re: round() wrong in Python 2.4?

                Antoon Pardon wrote:[color=blue]
                > Op 2005-09-13, Robert Kern schreef <rkern@ucsd.edu >:
                >[color=green]
                >>Jeremy Sanders wrote:
                >>[color=darkred]
                >>>Nils Grimsmo wrote:
                >>>
                >>>>Why did round() change in Python 2.4?
                >>>
                >>>It the usual floating point representation problem. 0.0225 cannot be
                >>>represente d exactly:[/color]
                >>
                >>That's not what he's asking about. He's asking why his Python 2.3 rounds
                >>0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's
                >>the change in behavior that he's concerned with and isn't just the usual
                >>floating point problem.[/color]
                >
                > I would say the usual floating point problem is involved.
                >
                > Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down.
                >
                > 0.0225 isn't representable and it happens that the actual number
                > you get differ. Now which number python should choose when it is
                > fed 0.0225, I don't know. But expressing the different behaviour
                > as a change in round, suggest that the O.P. would be wise to
                > learn about floating point problems[/color]

                Uhh, Python didn't change anything between 2.3 and 2.4 wrt round(). The
                reason he is seeing a difference is because the two executables were
                built with different compilers. The fact that the version of Python was
                different in the two cases obscures the real cause.

                Saying that 0.0225 can't be represented exactly as a binary floating
                point number is entirely true but is an incomplete answer. Yes,
                obviously binary floating point representations are involved. But one
                could always define a standard representation scheme that always gives
                the same answer for the same input. The fact is that for some reason
                there are two schemes being used. Another fact is that this has nothing
                to do with difference in the versions of Python he is using. Most of
                Python's floating point behavior is a platform-dependent accident (as
                Tim Peters always says), and Nils is using two slightly different platforms.

                --
                Robert Kern
                rkern@ucsd.edu

                "In the fields of hell where the grass grows high
                Are the graves of dreams allowed to die."
                -- Richard Harter

                Comment

                • Grant Edwards

                  #9
                  Re: round() wrong in Python 2.4?

                  On 2005-09-14, Robert Kern <rkern@ucsd.edu > wrote:[color=blue]
                  > Antoon Pardon wrote:[/color]
                  [color=blue][color=green]
                  >> 0.0225 isn't representable and it happens that the actual number
                  >> you get differ. Now which number python should choose when it is
                  >> fed 0.0225, I don't know. But expressing the different behaviour
                  >> as a change in round, suggest that the O.P. would be wise to
                  >> learn about floating point problems[/color]
                  >
                  > Uhh, Python didn't change anything between 2.3 and 2.4 wrt round().[/color]

                  That's what Antoon Pardon just said. The above paragraph says
                  that round() didn't change, and the fact that the OP thinks it
                  did indicates that the OP needs to learn more about FP.

                  --
                  Grant Edwards grante Yow! UH-OH!! We're out
                  at of AUTOMOBILE PARTS and
                  visi.com RUBBER GOODS!

                  Comment

                  • Magnus Lycka

                    #10
                    Re: round() wrong in Python 2.4?

                    Nils Grimsmo wrote:[color=blue]
                    > (Is this due to the different GCC used?)[/color]

                    Yes, but there are probably other nasty values with the
                    other CGG. Basically, what the code does, for a positive
                    number, is to calculate floor(0.0225*10 00.0+0.5)/1000.0.

                    As others have said: Don't trust this. If you use Python 2.4,
                    you can take advantage of the new decimal module, where no
                    floating point calculations are involved.

                    I tried with Python 2.2.3 on RH EL3, and for half a million
                    tested values that ended with 5 in the 4th decimal and used
                    ndigits=3, I got almost 3000 where it rounded towards zero,
                    and not towards infinity as the docs say. I.e. almost 0.6%
                    wrong.

                    Here is a more direct description of the problem in my system:[color=blue][color=green][color=darkred]
                    >>> math.floor(4.09 25*1.0*10.0*10. 0*10.0+0.5)[/color][/color][/color]
                    4093.0[color=blue][color=green][color=darkred]
                    >>> math.floor(4.09 35*1.0*10.0*10. 0*10.0+0.5)[/color][/color][/color]
                    4093.0[color=blue][color=green][color=darkred]
                    >>> math.floor(4.09 45*1.0*10.0*10. 0*10.0+0.5)[/color][/color][/color]
                    4095.0

                    Your 2.4 system is still strange though. I tried the
                    program below on a range of systems: RH Linux, HP-UX,
                    AIX, Solaris, on Sparc, PowerPC, PA-RISC, Intel Pentium
                    and AMD 64, and they always gave the same results with
                    Python 2.2.3 or Python 2.3.1.

                    Program:

                    for N in (1000,2000,3000 ,5000,10000,100 000,1000000):
                    buggy=0
                    for i in range(1,N,2):
                    f=i/2000.0
                    r=round(f,3)
                    if r<f:
                    buggy+=1
                    print "%7i %10f %5i %f%%" % (N/2,f,buggy,buggy *200./N)

                    Consistent output:

                    500 0.499500 0 0.000000%
                    1000 0.999500 12 1.200000%
                    1500 1.499500 12 0.800000%
                    2500 2.499500 24 0.960000%
                    5000 4.999500 47 0.940000%
                    50000 49.999500 369 0.738000%
                    500000 499.999500 2950 0.590000%

                    So, while N*1000.0 + 0.5 might sometimes be a little less than
                    an integer, even though N is an odd integer divided with 2000.0,
                    it seems that machines handling IEEE floating point numbers
                    agree about which numbers are affected, and 0.0225 should not
                    be a problem number:[color=blue][color=green][color=darkred]
                    >>> round(0.0225,3)[/color][/color][/color]
                    0.023

                    There have been problems with GCC's float() before though...

                    [color=blue]
                    > How do you correctly output floating-point numbers in 2.4?[/color]

                    There is no change here.
                    0.023 => 0.023 and 0.022 => 0.0219999999999 99999
                    in different Python versions. Use str() or %s etc.

                    BTW, the C source code looks like this:

                    static PyObject *
                    builtin_round(P yObject *self, PyObject *args)
                    {
                    double x;
                    double f;
                    int ndigits = 0;
                    int i;

                    if (!PyArg_ParseTu ple(args, "d|i:round" , &x, &ndigits))
                    return NULL;
                    f = 1.0;
                    i = abs(ndigits);
                    while (--i >= 0)
                    f = f*10.0;
                    if (ndigits < 0)
                    x /= f;
                    else
                    x *= f;
                    if (x >= 0.0)
                    x = floor(x + 0.5);
                    else
                    x = ceil(x - 0.5);
                    if (ndigits < 0)
                    x *= f;
                    else
                    x /= f;
                    return PyFloat_FromDou ble(x);
                    }

                    Perhaps one could argue that the code should be changed to
                    if (x >= 0.0)
                    x = floor(x + d + 0.5);
                    else
                    x = ceil(x - d - 0.5);
                    where d is a fairly small number, but this doesn't help in
                    the long run... For large enough floating point numbers,
                    the resolution of the floating point system gets bigger than
                    1! It might well be possible to make a round() function that
                    works just right in e.g. business accounting applications, where
                    money ranges between perhaps 0.01 and 1,000,000,000,0 00.00, but
                    it's much more difficult to make such a thing work for the
                    standard library, where we might want to use the whole range
                    available to floats.

                    Comment

                    • Robert Kern

                      #11
                      Re: round() wrong in Python 2.4?

                      Grant Edwards wrote:[color=blue]
                      > On 2005-09-14, Robert Kern <rkern@ucsd.edu > wrote:
                      >[color=green]
                      >>Antoon Pardon wrote:[/color]
                      >[color=green][color=darkred]
                      >>>0.0225 isn't representable and it happens that the actual number
                      >>>you get differ. Now which number python should choose when it is
                      >>>fed 0.0225, I don't know. But expressing the different behaviour
                      >>>as a change in round, suggest that the O.P. would be wise to
                      >>>learn about floating point problems[/color]
                      >>
                      >>Uhh, Python didn't change anything between 2.3 and 2.4 wrt round().[/color]
                      >
                      > That's what Antoon Pardon just said. The above paragraph says
                      > that round() didn't change, and the fact that the OP thinks it
                      > did indicates that the OP needs to learn more about FP.[/color]

                      Antoon:
                      "Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down."

                      --
                      Robert Kern
                      rkern@ucsd.edu

                      "In the fields of hell where the grass grows high
                      Are the graves of dreams allowed to die."
                      -- Richard Harter

                      Comment

                      • Reinhold Birkenfeld

                        #12
                        Re: round() wrong in Python 2.4?

                        Robert Kern wrote:[color=blue]
                        > Grant Edwards wrote:[color=green]
                        >> On 2005-09-14, Robert Kern <rkern@ucsd.edu > wrote:
                        >>[color=darkred]
                        >>>Antoon Pardon wrote:[/color]
                        >>[color=darkred]
                        >>>>0.0225 isn't representable and it happens that the actual number
                        >>>>you get differ. Now which number python should choose when it is
                        >>>>fed 0.0225, I don't know. But expressing the different behaviour
                        >>>>as a change in round, suggest that the O.P. would be wise to
                        >>>>learn about floating point problems
                        >>>
                        >>>Uhh, Python didn't change anything between 2.3 and 2.4 wrt round().[/color]
                        >>
                        >> That's what Antoon Pardon just said. The above paragraph says
                        >> that round() didn't change, and the fact that the OP thinks it
                        >> did indicates that the OP needs to learn more about FP.[/color]
                        >
                        > Antoon:
                        > "Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down."[/color]

                        Written in Pseudocode:

                        not (Py2.3 rounding up and Py2.4 rounding down)

                        Reinhold

                        Comment

                        • Robert Kern

                          #13
                          Re: round() wrong in Python 2.4?

                          Reinhold Birkenfeld wrote:[color=blue]
                          > Robert Kern wrote:[/color]
                          [color=blue][color=green]
                          >>Antoon:
                          >>"Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down."[/color]
                          >
                          > Written in Pseudocode:
                          >
                          > not (Py2.3 rounding up and Py2.4 rounding down)[/color]

                          I presumed the "isn't" was a typo given the "while."

                          --
                          Robert Kern
                          rkern@ucsd.edu

                          "In the fields of hell where the grass grows high
                          Are the graves of dreams allowed to die."
                          -- Richard Harter

                          Comment

                          • Robert Kern

                            #14
                            Re: round() wrong in Python 2.4?

                            Robert Kern wrote:[color=blue]
                            > Reinhold Birkenfeld wrote:
                            >[color=green]
                            >>Robert Kern wrote:[/color]
                            >[color=green][color=darkred]
                            >>>Antoon:
                            >>>"Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down."[/color]
                            >>
                            >>Written in Pseudocode:
                            >>
                            >>not (Py2.3 rounding up and Py2.4 rounding down)[/color]
                            >
                            > I presumed the "isn't" was a typo given the "while."[/color]

                            Oh never mind. I'm sorry I started this line of conversation.

                            --
                            Robert Kern
                            rkern@ucsd.edu

                            "In the fields of hell where the grass grows high
                            Are the graves of dreams allowed to die."
                            -- Richard Harter

                            Comment

                            • Antoon Pardon

                              #15
                              Re: round() wrong in Python 2.4?

                              Op 2005-09-14, Robert Kern schreef <rkern@ucsd.edu >:[color=blue]
                              > Antoon Pardon wrote:[color=green]
                              >> Op 2005-09-13, Robert Kern schreef <rkern@ucsd.edu >:
                              >>[color=darkred]
                              >>>Jeremy Sanders wrote:
                              >>>
                              >>>>Nils Grimsmo wrote:
                              >>>>
                              >>>>>Why did round() change in Python 2.4?
                              >>>>
                              >>>>It the usual floating point representation problem. 0.0225 cannot be
                              >>>>represent ed exactly:
                              >>>
                              >>>That's not what he's asking about. He's asking why his Python 2.3 rounds
                              >>>0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's
                              >>>the change in behavior that he's concerned with and isn't just the usual
                              >>>floating point problem.[/color]
                              >>
                              >> I would say the usual floating point problem is involved.
                              >>
                              >> Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down.
                              >>
                              >> 0.0225 isn't representable and it happens that the actual number
                              >> you get differ. Now which number python should choose when it is
                              >> fed 0.0225, I don't know. But expressing the different behaviour
                              >> as a change in round, suggest that the O.P. would be wise to
                              >> learn about floating point problems[/color]
                              >
                              > Uhh, Python didn't change anything between 2.3 and 2.4 wrt round().[/color]

                              That is what I said, or at least meant to say.
                              [color=blue]
                              > The
                              > reason he is seeing a difference is because the two executables were
                              > built with different compilers. The fact that the version of Python was
                              > different in the two cases obscures the real cause.[/color]

                              IMO the real cause is unimportant. The real cause can be a different
                              CPU or a different compilor or a different library. What it boils
                              down to is that you can't expect 0,0225 to be represented in a
                              value that will be rounded up.
                              [color=blue]
                              > Saying that 0.0225 can't be represented exactly as a binary floating
                              > point number is entirely true but is an incomplete answer. Yes,
                              > obviously binary floating point representations are involved. But one
                              > could always define a standard representation scheme that always gives
                              > the same answer for the same input.[/color]

                              Can we? I don't think we can, unless you are working with decimal
                              numbers. If you work with floats you are basically saying that
                              the program should choose the best approximation it can. That
                              approximation can differ according to circumstances. So one
                              must be prepared that round(0.225,3) can give different results
                              in different circumstances.
                              [color=blue]
                              > The fact is that for some reason
                              > there are two schemes being used. Another fact is that this has nothing
                              > to do with difference in the versions of Python he is using. Most of
                              > Python's floating point behavior is a platform-dependent accident (as
                              > Tim Peters always says), and Nils is using two slightly different platforms.[/color]

                              Yes and he wouldn't have blamed it on round, had he known or thought
                              about FP representations .

                              --
                              Antoon Pardon

                              Comment

                              Working...