Why Python 3?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Apr 20 23:43:17 EDT 2014


On Mon, 21 Apr 2014 09:24:09 +1000, Chris Angelico wrote:

> On Mon, Apr 21, 2014 at 8:52 AM, Gregory Ewing
> <greg.ewing at canterbury.ac.nz> wrote:
>> Chris Angelico wrote:
>>
>>> Truncating vs true is not the same as int vs float. If you mean to
>>> explicitly request float division, you call float() on one or both
>>> arguments. You're being explicit about something different.
>>
>>
>> If you know you're dealing with either ints or floats, which is true in
>> the vast majority of cases, then you know that / will always perform
>> float division.
> 
> And that's what I mean about the common non-trivial case. It's easy
> enough to come up with contrived or trivial cases that use any types,
> but in most cases, it'd be fine to explicitly call float() on one of the
> operands to explicitly request floating-point division. Choosing between
> two division operators is not the same thing as choosing a data type.

Nobody says that they are. Choosing between / and // means to choose 
between two different operator. / performs true division, the sort that 
you learn about in school (modulo the usual floating point issues -- 
floats are not mathematical reals). // performs division which floors 
towards negative infinity. (For positive values, that's equivalent to 
truncation.)

Hence the two special methods: __truediv__ and __floordiv__ (plus the 
reversed __r*__ versions). 

I think you need to stop thinking about "integer division", because (1) 
"integer division" is not well-defined, and (2) in the general case, // 
doesn't return an int, although it should return a value that is integer 
valued.

Why is integer division not well-defined? Because division of integers 
doesn't necessarily return an integer: the integers are not closed with 
the division operator. Cases like 10/5 are easy, that's just 2. What 
about 11/5 or -7/3? I can think of at least six things that "integer 
division" might do in those cases:

- round to nearest, ties round to even ("banker's rounding");
- round to nearest, ties round to odd;
- round towards positive infinity (ceiling);
- round towards negative infinity (floor);
- round towards zero (truncate);
- raise an exception;

so before talking about "integer division" we have to decide which of 
those apply. Python doesn't talk about integer division, well not 
officially, but talks about *floor division*. The nice thing about this 
is that there's no requirement that it return an actual int:

py> 11.0//2
5.0

just an integer-valued value. It's up to the class to decide how it works.


> Explicitly choosing float division:
> 
> x / float(y)

But here you're not choosing an *operator*, you're choosing a *type*. 
With this model, how do I distinguish between floor division and true 
division using, say, Fractions?

py> from fractions import Fraction as F
py> F(1799, 27)/F(3)  # True division.
Fraction(1799, 81)
py> F(1799, 27)//F(3)  # Floor division.
22

Converting to floats is not an option, since (1) it returns a float, not 
a Fraction, and (2) it introduces rounding errors:

py> F(1799, 27)/F(3) == F(1799, 27)/3.0
False

[...]
> Both explicit forms can be done cleanly without empowering the language
> with the magic of int/int->float.

It's hardly magic, and I really am having difficult in working out 
exactly what your objection to it is. Is it really as simple as 
"operations on ints should only return ints, like in C"?


-- 
Steven D'Aprano
http://import-that.dreamwidth.org/



More information about the Python-list mailing list