Integer and float division [was Re: Why Python 3?]

2014-04-20 Thread Steven D'Aprano
On Sat, 19 Apr 2014 19:37:31 +1000, Chris Angelico wrote:

 On Sat, Apr 19, 2014 at 7:25 PM, Ian Kelly ian.g.ke...@gmail.com
 wrote:
 The change from / denoting classic
 division to true division really only affects the case where both
 operands are integers, so far as I'm aware.  If you want to divide two
 integers and get a decimal result, then convert one or both of them to
 decimals first; you would have needed to do the same with classic
 division.
 
 If float were a perfect superset of int, and the only logical superset
 when you want non-integers, then it'd be fine. But if you're mixing int
 and Decimal, you have to explicitly convert, 

I don't think so. Operations on mixed int/Decimal arguments return 
Decimal. There's no conversion needed except to get the original Decimal 
number in the first place. (Decimal is not a built-in and there's no 
literal syntax for them.)

py from decimal import Decimal as D
py x, y = 1, D(2)
py x/y
Decimal('0.5')
py x//y
Decimal('0')


 whereas if you're mixing
 int and float, you don't. Why is it required to be explicit with Decimal
 but not float? Of all the possible alternate types, why float? Only
 because...

Because float is built-in and Decimal is not. Because Decimal wasn't 
introduced until Python 2.4 while the change to the division operator was 
first begun back in Python 2.2.

http://python.org/dev/peps/pep-0238/

Guido writes about why his decision to emulate C's division operator was 
a mistake:

http://python-history.blogspot.com.au/2009/03/problem-with-integer-division.html


 As for why float specifically, the division __future__ import has
 been around since 2.2, longer than either decimals or fractions.
 
 ... it already existed. There's no particular reason to up-cast to
 float, specifically, and it can cause problems with large integers -
 either by losing accuracy, or by outright overflowing.

If you reject C integer division, you have to do *something* with 1/2. 
Ideally you'll get a number numerically equal to one half. It can't be a 
Decimal, or a Fraction, because back in 2001 there were no Decimal or 
Fraction types, and even now in 2014 they aren't built-ins.

(Besides, both of those choices have other disadvantages. Fractions are 
potentially slow and painful, with excessive accuracy. See Guido's 
comments in his blog post above. And Decimal uses base 10 floating point, 
which is less suitable for serious numeric work than base 2 floats.)


 Suppose you take an integer, multiply it by 10, and divide it by 5. In
 theory, that's the same as multiplying by 2, right? 

That's a bit of a contrived example. But go on.


 Mathematically it
 is. In C it might not be, because the multiplication might overflow; but
 Python, like a number of other modern languages, has an integer type
 that won't overflow. 

Only since, um, version 2.2 I think. I don't have 2.1 easily available, 
but here's 1.5:


[steve@ando ~]$ python1.5
Python 1.5.2 (#1, Aug 27 2012, 09:09:18)  [GCC 4.1.2 20080704 (Red Hat 
4.1.2-52)] on linux2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
 2**31*10
Traceback (innermost last):
  File stdin, line 1, in ?
OverflowError: integer pow()


So don't forget the historical context of what you are discussing.



 In Python 2, doing the obvious thing works:
 
 x * 10 / 5 == x * 2

Ignoring old versions of Python 2.x, correct. But that is a contrived 
example. Mathematically x/5*10 also equals 2*x, but not with C division 
semantics. This is with Python 2.7:


 x = 7
 x/5*10, x*10/5, x*2
(10, 14, 14)

Let's try it with true (calculator) division:

 x/5*10, x*10/5, x*2
(14.0, 14.0, 14)


With a bit of effort, I'm sure you can find values of x where they are 
not all equal, but that's because floats only have a finite precision. In
general, true division is less surprising and causes fewer unexpected
truncation errors.

 
 In Python 3, you have to say Oh but I want my integer division to
 result in an integer:
 
 x * 10 // 5 == x * 2

No, // doesn't mean divide and coerce to an integer, it is 
*truncating* division. The type being truncated may choose to return
an int, but that's not compulsory:


 from decimal import Decimal as D
 x = D(23.5)
 x/4, x//4
(Decimal('5.875'), Decimal('5'))


 Yes, I can see that it's nice for simple interactive use. You type 1/2
 and you get back 0.5. But doesn't it just exchange one set of problems
 (dividing integers by integers rounds) 

It doesn't round, it truncates.

[steve@ando ~]$ python2.7 -c print round(799.0/100)
8.0
[steve@ando ~]$ python2.7 -c print 799/100
7


 for another set (floating
 point arithmetic isn't real number arithmetic)?

It's not like that avoiding that problem is an option.




-- 
Steven D'Aprano
http://import-that.dreamwidth.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Integer and float division [was Re: Why Python 3?]

2014-04-20 Thread Jussi Piitulainen
Steven D'Aprano writes:

 It doesn't round, it truncates.
 
 [steve@ando ~]$ python2.7 -c print round(799.0/100)
 8.0
 [steve@ando ~]$ python2.7 -c print 799/100
 7

Seems it floors rather than truncates:

$ python2.7 -c from math import trunc;print trunc(799./-100)
-7
$ python2.7 -c from math import floor;print floor(799./-100)
-8.0
$ python2.7 -c print 799/-100
-8

$ python3.2 -c print(799//-100)
-8
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Integer and float division [was Re: Why Python 3?]

2014-04-20 Thread Steven D'Aprano
On Sun, 20 Apr 2014 15:38:03 +0300, Jussi Piitulainen wrote:

 Steven D'Aprano writes:
 
 It doesn't round, it truncates.
 
 [steve@ando ~]$ python2.7 -c print round(799.0/100) 8.0
 [steve@ando ~]$ python2.7 -c print 799/100 7
 
 Seems it floors rather than truncates:
 
 $ python2.7 -c from math import trunc;print trunc(799./-100) -7
 $ python2.7 -c from math import floor;print floor(799./-100) -8.0
 $ python2.7 -c print 799/-100
 -8
 
 $ python3.2 -c print(799//-100)
 -8


Ah yes, so it does. Sorry for the confusion. This has been reported as a 
bug at least twice, but it is actually working as intended. // floors, 
not truncates towards zero.

http://bugs.python.org/issue19446
http://bugs.python.org/issue19574



-- 
Steven D'Aprano
http://import-that.dreamwidth.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Integer and float division [was Re: Why Python 3?]

2014-04-20 Thread Gregory Ewing

On Sat, 19 Apr 2014 19:37:31 +1000, Chris Angelico wrote:



In Python 3, you have to say Oh but I want my integer division to
result in an integer:


I don't see why that's such a big hardship.

There are clear advantages to having an explicit way to
request non-floor division. Whatever way is chosen for
that, some other way has to be chosen to request floor
division.

One could debate whether it would have been better to make
/ mean floor division and invent something else for
non-floor division, but then some people would complain
Oh, but I have to say I want my float division to return
a float!

Either way requires people to make some changes in their
habits.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list