# PEP 238 (revised)

Guido van Rossum guido at zope.com
Fri Jul 27 21:14:42 CEST 2001

> [Terry Reedy]
> > Given that one spurious argument for this proposal was the claim that
> > think it might be appropriate to warn here that the opposite is true
> > for sufficiently long longs, so that one may need to switch to
> > long//long to preserve accuracy.
>
> [Guido van Rossum]
> > I never bought the "preserving information" argument.  In general all
> > classic use of long/long should be switched to long//long, of course,
> > as should all classic use of int/int.

[Tim Peters]
> They should, but I'm still of the violent opinion that the "loss of
> information" argument is the key to what's wrong with
>
>     x = y / z
>
> today.  If it doesn't give the best result it can (given the limitations of
> internal representations) in all cases, polymorphism is still screwed in the
> cases where it happens not to, and "best result it can" has no objective
> meaning I can think of other than "closest possible to the infinitely
> precise result".  If it can return infinities or NaNs or raise OverflowError
> or silently underflow to 0 if y and z just happen to be longs with
> unfortunate values, we've only addressed the underlying problem for short
> ints.
>
> The problem with
>
>     2/3 == 0
>
> was never that the result "isn't a float"(!),

That depends on your point of view.  The problem was that it wasn't a
good approximation.  In a language (like Python today) where float is
the only type that can give you that approximation, the problem might
as well be thought of as "isn't a float".

> and flat-out disasters like
>
> >>> x = 1L << 2000
> >>> y = x
> >>> float(x)/y
> -1.#IND
> >>>
>
> can't be considered improvements for polymorphism even under the influence
> of strong drugs <wink>.
>
> The potential damage is most obvious with Python longs, but on boxes where
> Python ints have more bits of precision than doubles, that
>
>    x/1 == x
>
> will be false for some vanilla short ints x is also bad news.

But will it be false?  If x/1 returns a float, it certainly returns the
same float as float(x), and a comparison of float to int converts the
int to a float today.  Ditto for float vs. long.

> Throwing
> information away needlessly is the problem, and rigid conversion to float
> only sounds like "a cure" if you're picturing short ints on boxes where
> conversion to float can't lose info (which is most boxes today, but not all;
> 64-bit Linux is the most common exception).
>
> >>> x = 1L << 2000
> >>> y = x
> >>> x / y
>
> ought to return 1 (of some flavor), and
>
>     x/(y*2)
>
> ought to return 0.5 (so long as floats are the most accurate representation
> we have)
>
> and
>
>     x/1 == x
>
> ought to be true for short or long int x regardless of value or platform.
> "Preserving as much information as possible" is the only principle I see
> that explains why anyone in their right mind <wink> must agree with the
> claimed "ought to" behavior in those three examples.  It also explains why
> conversion to float is desirable if all you're picturing is int/int on
> current 32-bit boxes.

With the qualification "as much as possible", I agree.

By the time 3.0 comes around, (1L<<2000)/1 will probably return a
rational number.  But until we have added rationals, I think that for
most apps, long/long -> float is the only definition that is
consistent with the other requirements, which IMO are:

- longs behave like ints, only without the limitation on size;

- int/int must yield a close approximation of the mathematical result of
division;

- the result type should not depend on the input values.

The third requirement cannot be absolute (see the new meaning of
10**-100) but I still think it would be better if long/long true
division always returned a float than if it returned a long under
certain circumstances.  We cannot do anything about the underflow
either -- 1 / (1L<<2000) is 0 under the classic division rules too.

Until we have rationals, I'd be okay if long/long true division raised
an exception when unacceptable information loss would be the result --
but I'd be just as happy if it simply returned inf or 0.0 as a side
effect of the conversion to float.

I'm not willing to wait with the introduction of PEP 238 until we've
sorted out rationals.

People who don't want their longs to be truncated by true division
should not use true division with longs.

I expect that only mathematicians use longs outside the range of
IEEE double, and they will be wise enough to use //.