osdir.com

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Python-Dev] Change in Python 3's "round" behavior


I recently found out about Python 3's round-to-even change (via
https://github.com/cosmologicon/pywat!) and am having trouble finding
where that change was discussed.

I did find the revealingly-invalid bug report
https://bugs.python.org/issue32956 ("python 3 round bug"), so I asked
there, but wanted to invite anyone else on this list who might be
interested to help. If interested, please see the comments there
(copy/pasted below for convenience), and +nosy or comment on that
issue.

Thanks!

Joshua Bronson added the comment:

This was so surprising to me that I had to check some other languages
that I had handy. It turns out that not one of JavaScript, Ruby, Perl,
C++, Java, Go, or Rust agrees with Python. In fact they all agreed
with one another that 2.5 should round to 3. Examples below.

I understand from
https://github.com/cosmologicon/pywat/pull/40#discussion_r219962259
that "to always round up... can theoretically skew the data" but it's
not clear why that's a good enough reason to differ from the "round"
function in all these other languages (as opposed to e.g. offering
this alternative behavior in some additional "round_unskewed"
function).

I assume the rationale for having Python 3's "round" differ from that
of so many other languages was written down when this decision was
made, but I searched and couldn't find it. Could anyone link to it in
a comment here?

And would it be worth including rationale and a larger callout in the
https://docs.python.org/3/library/functions.html#round docs? The
documentation of this behavior is a bit buried among other things, and
the rationale for it is missing entirely.


$ node -e 'console.log(Math.round(2.5))'
3

$ ruby -e 'puts (2.5).round()'
3

$ perl -e 'use Math::Round; print round(2.5)'
3

$ cat test_round.cpp
#include <stdio.h>
#include <math.h>
int main(void) {
  printf("%f\n", round(2.5));
}
$ g++ test_round.cpp && ./a.out
3.000000

$ cat TestRound.java
class TestRound {
  public static void main(String[] args) {
    System.out.println(Math.round(2.5));
  }
}
$ javac TestRound.java && java TestRound
3

$ cat test_round.go
package main
import "fmt"
import "math"
func main() {
        fmt.Println(math.Round(2.5))
}
$ go build test_round.go && ./test_round
3

$ cat test_round.rs
fn main() {
  println!("{}", (2.5_f64).round());
}
$ rustc test_round.rs && ./test_round
3


Serhiy Storchaka added the comment:

See the discussion on the Python-Dev mailing list:
https://mail.python.org/pipermail/python-dev/2008-January/075863.html.

For C look at the rint() function. It is a common knowledge that
rounding half-to-even is what users want in most cases, but it is a
tiny bit more expensive in C. In Python the additional cost of such
rounding is insignificant.


Joshua Bronson added the comment:

Thanks Serhiy, I read the Python-Dev thread you linked to, but that
doesn't resolve the issues:

- Its topic is Python 2.6 (where this behavior does not occur) rather
than Python 3 (where it does).

- A few messages into the thread Guido does address Python 3, but in
fact says "I think the consensus is against round-to-even in 3.0" (see
https://mail.python.org/pipermail/python-dev/2008-January/075897.html).

- There is no discussion of the fact that this behavior differs from
the function named "round" in all the other programming languages I
mentioned, and whether it would therefore be better exposed as an
additional function (e.g. "round_to_even" or "round_unbiased", and in
the math or statistics package rather than builtins). Surprisingly,
Excel is the only other programming environment I saw discussed in the
thread. (And round(2.5) == 3 there.)

So that all suggests there must be some other thread or issue where
this change for Python 3 have been discussed, but I looked again and
could not find it.

The C "rint" example you gave just seems to prove the point that this
behavior should have a distinct name from "round".

Regarding:
> It is a common knowledge that rounding half-to-even is what users want in most cases

I don't think that's common knowledge; seems like citation needed?
Based on all the other languages where this differs (not to mention
Python 2), it's not clear users would want Python 3 to be the only
different one. And this is definitely a surprise for the majority of
programmers, whose experience with "round" is how it works everywhere
else. (This is making it into pywat after all:
https://github.com/cosmologicon/pywat/pull/40)

I can submit a PR for at least updating the docs about this (as per my
previous comment) if that would be welcomed.