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

Old Man Yells At Cloud

On Sun, Sep 17, 2017 at 11:03 PM, Steve D'Aprano
<steve+python at pearwood.info> wrote:
> On Sun, 17 Sep 2017 08:43 pm, Chris Angelico wrote:
>> On Sun, Sep 17, 2017 at 5:54 PM, Steve D'Aprano
>> <steve+python at pearwood.info> wrote:
>>> To even *know* that there are branches of maths where int/int isn't defined,
>>> you need to have learned aspects of mathematics that aren't even taught in
>>> most undergrad maths degrees. (I have a degree in maths, and if we ever
>>> covered areas where int/int was undefined, it was only briefly, and I've long
>>> since forgotten it.)
>> How about this:
>>>>> (1<<10000)/2
>> Traceback (most recent call last):
>>   File "<stdin>", line 1, in <module>
>> OverflowError: integer division result too large for a float
>> int/int is now undefined.
> No, it's perfectly defined: you get an overflow error if the arguments are too
> big to convert, or an underflow error if the denominator is too small, or a
> divide by zero error if you divide by zero...
> What do you make of this?
> py> float(1<<10000)/2.0
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> OverflowError: int too large to convert to float
> Would you like to argue that this shows that coercing ints to floats
> is "undefined"?
> Overflow and underflow errors are limitations of the float data type. We could
> fix that in a couple of ways:
> - silently underflow to zero (as Python already does!) or infinity, as needed;
> - use a bigger ~~boat~~ float;
> - or even an arbitrary precision float;
> - or return a rational number (fraction or similar);
> - or introduce a float context that allows you to specify the behaviour
>   that you want, as the decimal module does.
> There may be other solutions I haven't thought of. But these will do.
> The distinction between Python floats and real numbers ? is a red-herring. It
> isn't relevant.

You said:

>>> (I have a degree in maths, and if we ever
>>> covered areas where int/int was undefined, it was only briefly, and I've long
>>> since forgotten it.)

So what do YOU mean by "int/int" being "undefined"? And I referred to
real numbers because YOU referred to a degree in maths.

>> In Py2, it perfectly correctly returns
>> another integer (technically a long), but in Py3, it can't return a
>> float, so it errors out.
> Apart from your "correctly", which I disagree with, that's a reasonable
> description. The problem is that your example returns the correct result by
> accident. Forget such ludicrously large values, and try something more common:
> 1/2
> Most people aren't expecting integer division, but true division, and silently
> returning the wrong result (0 instead of 0.5) is a silent source of bugs.
> This isn't some theoretical problem that might, maybe, perhaps, be an issue for
> some people sometimes. It was a regular source of actual bugs leading to code
> silently returning garbage.

So why doesn't it return a fractions.Fraction instead? That way, you
still get "one half" instead of zero, but it's guaranteed to be
accurate. And having 1/3 be a literal meaning "one third" would avoid
all the problems of "1/3 + 1/3 + 1/3 != 3/3". What is the
justification for int/int => float and not rational?

>> In Python 2 and 3, a small integer can be implicitly promoted to float:
>>>>> user_input = 3.14159
>>>>> print(user_input + 1)
>> 4.14159
> Yes, as it should. Why force the user to call float() on one argument when the
> interpreter can do it? What advantage is there?
> Can you demonstrate any failure of dividing two ints n/m which wouldn't equally
> fail if you called float(n)/float(m)? I don't believe that there is any such
> failure mode. Forcing the user to manually coerce to floats doesn't add any
> protection.

I don't think there is either, but by forcing people to coerce to
float, you force them to accept the consequences of floats. Again,
rationals (fractions.Fraction), implemented with a pair of
arbitrary-precision integers, are a superset of integers, so you can
genuinely upcast.

Upcasting from one type to a non-superset of that type is problematic.
Upcasting to a perfect superset isn't.