Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Chris Barker
>
>
> Does anybody know examples of the correct use of float.is_integer() in
> real programs? For now it looks just like a bug magnet. I suggest to
> deprecate it in 3.7 or 3.8 and remove in 3.9 or 3.10.


+1

It really doesn’t appear to be the right solution for any problem.

-CHB
-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Guido van Rossum
I searched 6M LoC of Python code at Dropbox and found only three uses. They
seem legit. Two are about formatting a number that's given as a float,
deciding whether to print a float as 42 or 3.14. The third is attempting a
conversion from float to integer where a non-integer must raise a specific
exception (the same function also supports a string as long as it can be
parsed as an int).

I don't doubt we would get by if is_integer() was deprecated.


On Wed, Mar 21, 2018 at 3:31 AM, Chris Barker  wrote:

>
>> Does anybody know examples of the correct use of float.is_integer() in
>> real programs? For now it looks just like a bug magnet. I suggest to
>> deprecate it in 3.7 or 3.8 and remove in 3.9 or 3.10.
>
>
> +1
>
> It really doesn’t appear to be the right solution for any problem.
>
> -CHB
> --
>
> Christopher Barker, Ph.D.
> Oceanographer
>
> Emergency Response Division
> NOAA/NOS/OR&R(206) 526-6959   voice
> 7600 Sand Point Way NE   (206) 526-6329   fax
> Seattle, WA  98115   (206) 526-6317   main reception
>
> chris.bar...@noaa.gov
>
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
> guido%40python.org
>
>


-- 
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Steve Holden
On Wed, Mar 21, 2018 at 3:08 PM, Guido van Rossum  wrote:

> I searched 6M LoC of Python code at Dropbox and found only three uses.
> They seem legit. Two are about formatting a number that's given as a float,
> deciding whether to print a float as 42 or 3.14. The third is attempting a
> conversion from float to integer where a non-integer must raise a specific
> exception (the same function also supports a string as long as it can be
> parsed as an int).
>
> I don't doubt we would get by if is_integer() was deprecated.
>
> ​Since code that's been deleted can't have bugs, +1.​
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Robert Smallshire
Here's an excerpted (and slightly simplified for consumption here) usage of
float.is_integer() from the top of a function which does some
convolution/filtering in a geophysics application. I've mostly seen it used
in guard clauses in this way to reject either illegal numeric arguments
directly, or particular combinations of arguments as in this case:

def filter_convolve(x, y, xf, yf, stride=1, padding=1):
x_out = (x - xf + 2*padding) / stride + 1
y_out = (y - yf + 2*padding) / stride + 1

if not (x_out.is_integer() and y_out.is_integer()):
raise ValueError("Invalid convolution filter_convolve({x},
{y}, {xf}, {yf}, {stride}, {padding})"
 .format(x=x, y=y, xf=xf, yf=yf,
stride=stride, padding=padding))
x_out = int(x_out)
y_out = int(y_out)

# ...

Of course, there are other ways to do this check, but the approach here is
obvious and easy to comprehend.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Mark Dickinson
I'd prefer to see `float.is_integer` stay. There _are_ occasions when one
wants to check that a floating-point number is integral, and on those
occasions, using `x.is_integer()` is the one obvious way to do it. I don't
think the fact that it can be misused should be grounds for deprecation.

As far as real uses: I didn't find uses of `is_integer` in our code base
here at Enthought, but I did find plenty of places where it _could_
reasonably have been used, and where something less readable like `x % 1 ==
0` was being used instead. For evidence that it's generally useful: it's
already been noted that the decimal module uses it internally. The mpmath
package defines its own "isint" function and uses it in several places: see
https://github.com/fredrik-johansson/mpmath/blob/2858b1000ffdd8596defb50381dcb83de2b6/mpmath/ctx_mp_python.py#L764.
MPFR also has an mpfr_integer_p predicate:
http://www.mpfr.org/mpfr-current/mpfr.html#index-mpfr_005finteger_005fp.

A concrete use-case: suppose you wanted to implement the beta function (
https://en.wikipedia.org/wiki/Beta_function) for real arguments in Python.
You'll likely need special handling for the poles, which occur only for
some negative integer arguments, so you'll need an is_integer test for
those. For small positive integer arguments, you may well want the accuracy
advantage that arises from computing the beta function in terms of
factorials (giving a correctly-rounded result) instead of via the log of
the gamma function. So again, you'll want an is_integer test to identify
those cases. (Oddly enough, I found myself looking at this recently as a
result of the thread about quartile definitions: there are links between
the beta function, the beta distribution, and order statistics, and the
(k-1/3)/(n+1/3) expression used in the recommended quartile definition
comes from an approximation to the median of a beta distribution with
integral parameters.)

Or, you could look at the SciPy implementation of the beta function, which
does indeed do the C equivalent of is_integer in many places:
https://github.com/scipy/scipy/blob/11509c4a98edded6c59423ac44ca1b7f28fba1fd/scipy/special/cephes/beta.c#L67

In sum: it's an occasionally useful operation; there's no other obvious,
readable spelling of the operation that does the right thing in all cases,
and it's _already_ in Python! In general, I'd think that deprecation of an
existing construct should not be done lightly, and should only be done when
there's an obvious and significant benefit to that deprecation. I don't see
that benefit here.

-- 
Mark
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread David Mertz
I've been using and teaching python for close to 20 years and I never
noticed that x.is_integer() exists until this thread. I would say the "one
obvious way" is less than obvious.

On the other hand, `x == int(x)` is genuinely obvious... and it immediately
suggests the probably better `math.isclose(x, int(x))` that is what you
usually mean.

On Wed, Mar 21, 2018, 2:08 PM Mark Dickinson  wrote:

> I'd prefer to see `float.is_integer` stay. There _are_ occasions when one
> wants to check that a floating-point number is integral, and on those
> occasions, using `x.is_integer()` is the one obvious way to do it. I don't
> think the fact that it can be misused should be grounds for deprecation.
>
> As far as real uses: I didn't find uses of `is_integer` in our code base
> here at Enthought, but I did find plenty of places where it _could_
> reasonably have been used, and where something less readable like `x % 1 ==
> 0` was being used instead. For evidence that it's generally useful: it's
> already been noted that the decimal module uses it internally. The mpmath
> package defines its own "isint" function and uses it in several places: see
> https://github.com/fredrik-johansson/mpmath/blob/2858b1000ffdd8596defb50381dcb83de2b6/mpmath/ctx_mp_python.py#L764.
> MPFR also has an mpfr_integer_p predicate:
> http://www.mpfr.org/mpfr-current/mpfr.html#index-mpfr_005finteger_005fp.
>
> A concrete use-case: suppose you wanted to implement the beta function (
> https://en.wikipedia.org/wiki/Beta_function) for real arguments in
> Python. You'll likely need special handling for the poles, which occur only
> for some negative integer arguments, so you'll need an is_integer test for
> those. For small positive integer arguments, you may well want the accuracy
> advantage that arises from computing the beta function in terms of
> factorials (giving a correctly-rounded result) instead of via the log of
> the gamma function. So again, you'll want an is_integer test to identify
> those cases. (Oddly enough, I found myself looking at this recently as a
> result of the thread about quartile definitions: there are links between
> the beta function, the beta distribution, and order statistics, and the
> (k-1/3)/(n+1/3) expression used in the recommended quartile definition
> comes from an approximation to the median of a beta distribution with
> integral parameters.)
>
> Or, you could look at the SciPy implementation of the beta function, which
> does indeed do the C equivalent of is_integer in many places:
> https://github.com/scipy/scipy/blob/11509c4a98edded6c59423ac44ca1b7f28fba1fd/scipy/special/cephes/beta.c#L67
>
> In sum: it's an occasionally useful operation; there's no other obvious,
> readable spelling of the operation that does the right thing in all cases,
> and it's _already_ in Python! In general, I'd think that deprecation of an
> existing construct should not be done lightly, and should only be done when
> there's an obvious and significant benefit to that deprecation. I don't see
> that benefit here.
>
> --
> Mark
>
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/mertz%40gnosis.cx
>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Guido van Rossum
On Wed, Mar 21, 2018 at 11:14 AM, David Mertz  wrote:

> I've been using and teaching python for close to 20 years and I never
> noticed that x.is_integer() exists until this thread. I would say the "one
> obvious way" is less than obvious.
>
> On the other hand, `x == int(x)` is genuinely obvious... and it
> immediately suggests the probably better `math.isclose(x, int(x))` that is
> what you usually mean.
>

We can argue about this forever, but I don't think I would have come up
with that either when asked "how to test a float for being a whole number".
I would probably have tried "x%1 == 0" which is terrible. I like to have an
API that doesn't have the pitfalls of any of the "obvious" solutions that
numerically naive people would come up with, and x.is_integer() is it.
Let's keep it.

-- 
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Tim Peters
[David Mertz]
> I've been using and teaching python for close to 20 years and I never
> noticed that x.is_integer() exists until this thread.

Except it was impossible to notice across most of those years, because
it didn't exist across most of those years ;-)


> I would say the "one obvious way" is less than obvious.

When it was introduced, it _became_ the one obvious way.


> On the other hand, `x == int(x)` is genuinely obvious..

But a bad approach:  it can raise OverflowError (for infinite x); it
can raise ValueError (for x a NaN); and can waste relative mountains
of time creating huge integers, e.g.,

>>> int(1e306)
117216064596736454828831087825013238982328892017892380671244575047987920451875459594568606138861698291060311049225532948520696938805711440650122628514669428460356992624968028329550689224175284346730060716088829214255439694630119794546505512415617982143262670862918816362862119154749127262208

In Python 2, x == math.floor(x) was much better on the latter count,
but not in Python 3 (math.floor used to return a float, but returns an
int now).


As to Serhiy's `not x % 1.0`, after 5 minutes I gave up trying to
prove it's always correct.  Besides infinities and NaNs, there's also
that Python's float mod can be surprising:

>>> (-1e-20) % 1.0
1.0

There isn't a "clean" mathematical definition of what Python's float %
does, which is why proof is strained.  In general, the "natural"
result is patched when and if needed to maintain that

x == y*(x//y) + x%y

is approximately true.  The odd % result above is a consequence of
that, and that (-1e-20) // 1.0 is inarguably -1.0.


> and it immediately suggests the probably better `math.isclose(x, int(x))` that
> is what you usually mean.

Even in some of the poor cases Serhiy found, that wouldn't be a lick
better.  For example,

math.isclose(x/5, int(x/5))

is still a plain wrong way to check whether x is divisible by 5.

>>> x = 1e306
>>> math.isclose(x/5, int(x/5))
True
>>> x/5 == int(x/5)
True
>>> int(x) % 5
3

The problem there isn't  how "is it an integer?" is spelled, it's that
_any_ way of spelling "is it an integer?" doesn't answer the question
they're trying to answer.  They're just plain confused about how
floating point works.  The use of `.is_integer()` (however spelled!)
isn't the cause of that, it's a symptom.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread David Mertz
On Wed, Mar 21, 2018 at 3:02 PM, Tim Peters  wrote:

> [David Mertz]
> > I've been using and teaching python for close to 20 years and I never
> > noticed that x.is_integer() exists until this thread.
>
> Except it was impossible to notice across most of those years, because
> it didn't exist across most of those years ;-)
>

That's probably some of the reason.  I wasn't sure if someone used the time
machine to stick it back into Python 1.4.


> > On the other hand, `x == int(x)` is genuinely obvious..
>
> But a bad approach:  it can raise OverflowError (for infinite x); it
> can raise ValueError (for x a NaN);


These are the CORRECT answers! Infinity neither is nor is not an integer.
Returning a boolean as an answer is bad behavior; I might argue about
*which* exception is best, but False is not a good answer to
`float('inf').is_integer()`.  Infinity is neither in the Reals nor in the
Integers, but it's just as much the limit of either.

Likewise Not-a-Number isn't any less an integer than it is a real number
(approximated by a floating point number).  It's NOT a number, which is
just as much not an integer.


> and can waste relative mountains
> of time creating huge integers, e.g.,
>

True enough. But it's hard to see where that should matter.  No floating
point number on the order of 1e306 is sufficiently precise as to be an
integer in any meaningful sense.  If you are doing number theory with
integers of that size (or larger is perfectly fine too) the actual test is
`isinstance(x, int)`.  Using a float is just simply wrong for the task to
start with, whether or not those bits happen to represent something
Integral... the only case where you should see this is
"measuring/estimating something VERY big, very approximately."

For example, this can be true (even without reaching inf):

>>> x.is_integer()
True
>>> (math.sqrt(x**2)).is_integer()
False

The problem there isn't  how "is it an integer?" is spelled, it's that
> _any_ way of spelling "is it an integer?" doesn't answer the question
> they're trying to answer.  They're just plain confused about how
> floating point works.  The use of `.is_integer()` (however spelled!)
> isn't the cause of that, it's a symptom.
>

Agreed!

-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Mark Dickinson
On Wed, Mar 21, 2018 at 8:49 PM, David Mertz  wrote:

> For example, this can be true (even without reaching inf):
>
> >>> x.is_integer()
> True
> >>> (math.sqrt(x**2)).is_integer()
> False
>

If you have a moment to share it, I'd be interested to know what value of
`x` you used to achieve this, and what system you were on. This can't
happen under IEEE 754 arithmetic.

-- 
Mark
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Tim Peters
Note:  this is a top-posted essay much more about floating-point
philosophy than about details.  Details follow from the philosophy,
and if philosophies don't match the desired details will never match
either.

Understanding floating point requires accepting that they're a funky
subset of rational numbers, augmented with some oddballs (NaNs,
"infinities", minus zero).  At best the reals are a vague inspiration,
and floats have their own terminology serving their actual nature.
Thinking about reals instead is often unhelpful.

For example, it's bog standard terminology to call all IEEE-754 values
that aren't infinities or NaNs "finite".  Which, by no coincidence, is
how Python's math.isfinite() discriminates.  Within the finites -
which are all rational numbers - the distinction between integers and
non-integers is obvious, but only after you're aware of it and give it
some thought.  Which most people aren't and don't - but that's no
reason to prevent the rest of us from getting work done ;-)

This isn't anything new in Python - it's as old as floating-point.
For example, look up C's ancient "modf" function (which breaks a
float/double into its "integer" and "fractional" parts, and treats all
finite floats of sufficiently large magnitude as having fractional
parts of 0.0 - because they in are fact exact integers).

The idea that floats are "just approximations - so all kinds of slop
is acceptable and all kinds of fear inescapable" went out of style
when IEEE-754 was introduced.  That standard codified an alternative
view:  that functions on floats should behave as if their inputs were
_exactly_ correct, and - given that - produce the closest
representable value to the infinitely precise result.  That proved to
be extremely valuable in practice, allowing the development of
shorter, faster, more robust, and more accurate numerical algorithms.

The trend ever since has been to do more & more along those lines,
from trig functions doing argument reduction as if pi were represented
with infinite precision, to adding single-rounding dot product
primitives (all again acting as if all the inputs were exactly
correct).

Since that approach has been highly productive in real life, it's the
one I favor.  Arguments like "no floating point number on the order of
1e306 is sufficiently precise as to be an integer in any meaningful
sense" don't even start to get off the ground in that approach.  Maybe
in 1970 ;-)  You can have no actual idea of whether 1e306 is exactly
right or off by a factor of a million just from staring at it, and
real progress has been made by assuming all values are exactly what
they appear to be, then acting accordingly.  If you want to model that
some values are uncertain, that's fine, but then you need something
like interval arithmetic instead.

>From that fundamental "take floats exactly at face value" view, what
.is_integer() should do for floats is utterly obvious:  there is no
possible argument about whether a given IEEE-754 float is or is not an
integer, provided you're thinking about IEEE-754 floats (and not,
e.g., about mathematical reals), and making even a tiny attempt to
honor the spirit of the IEEE-754 standard.

Whether that's _useful_ to you depends on the application you're
writing at the time.  The advantage of the philosophy is that it often
gives clear guidance about what implementations "should do"
regardless, and following that guidance has repeatedly proved to be a
boon to those writing numerical methods.  And, yes, also a pain in the
ass ;-)

--- nothing new below ---

On Wed, Mar 21, 2018 at 3:49 PM, David Mertz  wrote:
> On Wed, Mar 21, 2018 at 3:02 PM, Tim Peters  wrote:
>>
>> [David Mertz]
>> > I've been using and teaching python for close to 20 years and I never
>> > noticed that x.is_integer() exists until this thread.
>>
>> Except it was impossible to notice across most of those years, because
>> it didn't exist across most of those years ;-)
>
>
> That's probably some of the reason.  I wasn't sure if someone used the time
> machine to stick it back into Python 1.4.
>
>>
>> > On the other hand, `x == int(x)` is genuinely obvious..
>>
>> But a bad approach:  it can raise OverflowError (for infinite x); it
>> can raise ValueError (for x a NaN);
>
>
> These are the CORRECT answers! Infinity neither is nor is not an integer.
> Returning a boolean as an answer is bad behavior; I might argue about
> *which* exception is best, but False is not a good answer to
> `float('inf').is_integer()`.  Infinity is neither in the Reals nor in the
> Integers, but it's just as much the limit of either.
>
> Likewise Not-a-Number isn't any less an integer than it is a real number
> (approximated by a floating point number).  It's NOT a number, which is just
> as much not an integer.
>
>>
>> and can waste relative mountains
>> of time creating huge integers, e.g.,
>
>
> True enough. But it's hard to see where that should matter.  No floating
> point number on the order of 1e306 is sufficientl

Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Tim Peters
[David Mertz ]
>> For example, this can be true (even without reaching inf):
>>
>> >>> x.is_integer()
>> True
>> >>> (math.sqrt(x**2)).is_integer()
>> False

[Mark Dickinson  ]
> If you have a moment to share it, I'd be interested to know what value of
> `x` you used to achieve this, and what system you were on. This can't happen
> under IEEE 754 arithmetic.

I expect it might happen under one of the directed rounding modes
(like "to +infinity").

But under 754 binary round-nearest/even arithmetic, it's been formally
proved that sqrt(x*x) == x exactly for all non-negative finite x such
that x*x neither overflows nor underflows (and .as_integer() has
nothing to do with that very strong result):

https://hal.inria.fr/hal-01148409/document

OTOH, the paper notes that it's not necessarily true for IEEE decimal
arithmetic; e.g.,

>>> import decimal
>>> decimal.getcontext().prec = 4
>>> (decimal.Decimal("31.66") ** 2).sqrt()  # result is 1 ulp smaller
Decimal('31.65')

>>> decimal.getcontext().prec = 5
>>> (decimal.Decimal("31.660") ** 2).sqrt() # result is 1 ulp larger
Decimal('31.661')
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Devin Jeanpierre
> [Mark Dickinson  ]
>> If you have a moment to share it, I'd be interested to know what value of
>> `x` you used to achieve this, and what system you were on. This can't happen
>> under IEEE 754 arithmetic.
>
> I expect it might happen under one of the directed rounding modes
> (like "to +infinity").

PyPy (5.8):

 x = 1e300
 x.is_integer()
True
 math.sqrt(x**2).is_integer()
False
 x**2
inf

(It gives an OverflowError on my CPython installs.)

I believe this is allowed, and Python is not required to raise
OverflowError here:
https://docs.python.org/3.6/library/exceptions.html#OverflowError
says:

> for historical reasons, OverflowError is sometimes raised for integers that 
> are outside a required range. Because of the lack of standardization of 
> floating point exception handling in C, most floating point operations are 
> not checked

-- Devin
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Chris Barker
On Wed, Mar 21, 2018 at 11:43 PM, Tim Peters  wrote:

> Note:  this is a top-posted essay much more about floating-point
> philosophy than about details.  Details follow from the philosophy,
> and if philosophies don't match the desired details will never match
> either.
>

but of course :-)


> From that fundamental "take floats exactly at face value" view, what
> .is_integer() should do for floats is utterly obvious:


sure -- but I don't think anyone is arguing that -- the question is whether
the function should exist -- and that means not "how should it work?" or
"is it clearly and appropriately defined?" but rather, "is it the "right"
thing to do in most cases, when deployed by folks that haven't thought
deeply about floating point.

> Whether that's _useful_ to you depends on the application you're

> writing at the time.


exactly.

I think pretty much all the real world code that's been shown here for
using .is_integer() is really about type errors (issues). The function at
hand really wants integer inputs -- but wants to allow the user to be
sloppy and provide a float type that happens to be an int. Given Python's
duck-typing nature, maybe that's a good thing? I know I really discourage
dynamic type checking

Also, every example has been for small-ish integers -- exponents,
factorials, etc -- not order 1e300 -- or inf or NaN, etc.

Finally, the use-cases where the value that happens-to-be-an-int is
computed via floating point -- .is_integer() is probably the wrong check --
you probably want  isclose().

The other use-cases: and floor() and ceil() and round() all produce actual
integers -- so no need for that anymore.

All this points to: we don't need .is_integer

All the being said -- the standard for depreciation is much higher bar than
not-adding-it-in-the-first-place.

-CHB


-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Tim Peters
[Devin Jeanpierre ]
> PyPy (5.8):
>  x = 1e300
>  x.is_integer()
> True
>  math.sqrt(x**2).is_integer()
> False
>  x**2
> inf

I think you missed that David said "even without reaching inf" (you
did reach inf), and that I said "such that x*x neither overflows nor
underflows".  Those are technical words related to IEEE-754:  your x*x
sets the IEEE overflow flag, although CPython may or may not raise the
Python OverflowError exception.

>
> (It gives an OverflowError on my CPython installs.)
>
> I believe this is allowed, and Python is not required to raise
> OverflowError here:
> https://docs.python.org/3.6/library/exceptions.html#OverflowError
> says:
>
>> for historical reasons, OverflowError is sometimes raised for integers that 
>> are outside a required range. Because of the lack of standardization of 
>> floating point exception handling in C, most floating point operations are 
>> not checked

You can avoid the OverflowError (but not the IEEE overflow condition!)
under CPython by multiplying instead:

>>> x = 1e300
>>> x*x
inf
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread David Mertz
Ok. I'm wrong on that example.

On Wed, Mar 21, 2018, 9:11 PM Tim Peters  wrote:

> [David Mertz ]
> >> For example, this can be true (even without reaching inf):
> >>
> >> >>> x.is_integer()
> >> True
> >> >>> (math.sqrt(x**2)).is_integer()
> >> False
>
> [Mark Dickinson  ]
> > If you have a moment to share it, I'd be interested to know what value of
> > `x` you used to achieve this, and what system you were on. This can't
> happen
> > under IEEE 754 arithmetic.
>
> I expect it might happen under one of the directed rounding modes
> (like "to +infinity").
>
> But under 754 binary round-nearest/even arithmetic, it's been formally
> proved that sqrt(x*x) == x exactly for all non-negative finite x such
> that x*x neither overflows nor underflows (and .as_integer() has
> nothing to do with that very strong result):
>
> https://hal.inria.fr/hal-01148409/document
>
> OTOH, the paper notes that it's not necessarily true for IEEE decimal
> arithmetic; e.g.,
>
> >>> import decimal
> >>> decimal.getcontext().prec = 4
> >>> (decimal.Decimal("31.66") ** 2).sqrt()  # result is 1 ulp smaller
> Decimal('31.65')
>
> >>> decimal.getcontext().prec = 5
> >>> (decimal.Decimal("31.660") ** 2).sqrt() # result is 1 ulp larger
> Decimal('31.661')
>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Tim Peters
[Chris Barker ]
> ...
> ... "is it the "right" thing to do in most cases, when deployed by folks
> that haven't thought deeply about floating point.

Gimme a break ;-)  Even people who _believe_ they've thought about
floating point still litter the bug tracker with

>>> .1 + .2
0.30004

"bug reports".  .is_integer() is easy to explain compared to that  -
and you have to go out of your way to use it.

> ...
> I think pretty much all the real world code that's been shown here for using
> .is_integer() is really about type errors (issues). The function at hand
> really wants integer inputs -- but wants to allow the user to be sloppy and
> provide a float type that happens to be an int. Given Python's duck-typing
> nature, maybe that's a good thing? I know I really discourage dynamic type
> checking

So you identified a use case.  One you don't approve of (nor do I),
but not strongly enough to demand they suffer instead ;-)


> Also, every example has been for small-ish integers -- exponents,
> factorials, etc -- not order 1e300 -- or inf or NaN, etc.
>
> Finally, the use-cases where the value that happens-to-be-an-int is computed
> via floating point -- .is_integer() is probably the wrong check -- you
> probably want  isclose().

Everyone who has implemented a production math library can recall
cases where the functionality was needed.  Here, that includes at
least Stefan Krah and me.  You could also follow the link from Mark
Dickinson to SciPy's implementation of the beta function.

In every case I've needed the functionality, isclose() would have been
utterly useless.  Behold:

>>> (-1.0) ** 3.0
-1.0
>>> (-1.0) ** 3.0001  # different result _type_
(-1-3.142007854859299e-12j)
>>> math.isclose(3.0, 3.0001)
True

And another showing that the same functionality is needed regardless
of how large the power:

>>> (-1.0) ** 1e300  # an even integer power
1.0

When implementing an externally defined standard, when it says "and if
such-and-such is an integer ...", it _means_ exactly an integer, not
"or a few ULP away from an integer".  IEEE pow()-like functions
bristle with special cases for integers.

>>> (-math.inf) ** 3.1
inf
>>> (-math.inf) ** 3.0 # note: this one has a negative result (odd integer 
>>> power)
-inf
>>> (-math.inf) ** 2.9
inf


> ...
> All this points to: we don't need .is_integer

I'll grant that you don't think you need it.  So don't use it ;-)


> All the being said -- the standard for depreciation is much higher bar than
> not-adding-it-in-the-first-place.

I would not have added it as a method to begin with - but I agree with
Guido that it doesn't reach the bar for deprecation.  The only
examples of "bad" uses we saw were from people still so naive about
floating-point behavior that they'll easily fall into other ways to
get it wrong.  What we haven't seen:  a single person here saying "you
know, I think _I'd_ be seduced into misusing it!".  It's not
_inherently_ confusing at all.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Guido van Rossum
OK, we'll keep float.is_integer(), and that's a pronouncement, so that we
can hopefully end this thread soon.

It should also be added to int. After all that's what started this thread,
with the observation that mypy and PEP 484 consider an int valid whenever a
float is expected.

Since PEP 484 and mypy frown upon the numeric tower I don't care too much
about whether it's added it there (or to Decimal) but given that we're
keeping float.is_integer() and adding int.is_integer(), I don't see what's
gained by not adding it to the numeric tower and Decimal either.

Numpy can do what it likes, it doesn't play by the same rules as the stdlib
anyway.

On Wed, Mar 21, 2018 at 7:29 PM, Tim Peters  wrote:

> [Chris Barker ]
> > ...
> > ... "is it the "right" thing to do in most cases, when deployed by folks
> > that haven't thought deeply about floating point.
>
> Gimme a break ;-)  Even people who _believe_ they've thought about
> floating point still litter the bug tracker with
>
> >>> .1 + .2
> 0.30004
>
> "bug reports".  .is_integer() is easy to explain compared to that  -
> and you have to go out of your way to use it.
>
> > ...
> > I think pretty much all the real world code that's been shown here for
> using
> > .is_integer() is really about type errors (issues). The function at hand
> > really wants integer inputs -- but wants to allow the user to be sloppy
> and
> > provide a float type that happens to be an int. Given Python's
> duck-typing
> > nature, maybe that's a good thing? I know I really discourage dynamic
> type
> > checking
>
> So you identified a use case.  One you don't approve of (nor do I),
> but not strongly enough to demand they suffer instead ;-)
>
>
> > Also, every example has been for small-ish integers -- exponents,
> > factorials, etc -- not order 1e300 -- or inf or NaN, etc.
> >
> > Finally, the use-cases where the value that happens-to-be-an-int is
> computed
> > via floating point -- .is_integer() is probably the wrong check -- you
> > probably want  isclose().
>
> Everyone who has implemented a production math library can recall
> cases where the functionality was needed.  Here, that includes at
> least Stefan Krah and me.  You could also follow the link from Mark
> Dickinson to SciPy's implementation of the beta function.
>
> In every case I've needed the functionality, isclose() would have been
> utterly useless.  Behold:
>
> >>> (-1.0) ** 3.0
> -1.0
> >>> (-1.0) ** 3.0001  # different result _type_
> (-1-3.142007854859299e-12j)
> >>> math.isclose(3.0, 3.0001)
> True
>
> And another showing that the same functionality is needed regardless
> of how large the power:
>
> >>> (-1.0) ** 1e300  # an even integer power
> 1.0
>
> When implementing an externally defined standard, when it says "and if
> such-and-such is an integer ...", it _means_ exactly an integer, not
> "or a few ULP away from an integer".  IEEE pow()-like functions
> bristle with special cases for integers.
>
> >>> (-math.inf) ** 3.1
> inf
> >>> (-math.inf) ** 3.0 # note: this one has a negative result (odd integer
> power)
> -inf
> >>> (-math.inf) ** 2.9
> inf
>
>
> > ...
> > All this points to: we don't need .is_integer
>
> I'll grant that you don't think you need it.  So don't use it ;-)
>
>
> > All the being said -- the standard for depreciation is much higher bar
> than
> > not-adding-it-in-the-first-place.
>
> I would not have added it as a method to begin with - but I agree with
> Guido that it doesn't reach the bar for deprecation.  The only
> examples of "bad" uses we saw were from people still so naive about
> floating-point behavior that they'll easily fall into other ways to
> get it wrong.  What we haven't seen:  a single person here saying "you
> know, I think _I'd_ be seduced into misusing it!".  It's not
> _inherently_ confusing at all.
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
> guido%40python.org
>



-- 
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Greg Ewing

Tim Peters wrote:

from trig functions doing argument reduction as if pi were represented
with infinite precision,


That sounds like an interesting trick! Can you provide
pointers to any literature describing how it's done?

Not doubting it's possible, just curious.

--
Greg
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-21 Thread Tim Peters
[Tim]
>> from trig functions doing argument reduction as if pi were represented
>> with infinite precision,

[Greg Ewing ]
> That sounds like an interesting trick! Can you provide
> pointers to any literature describing how it's done?
>
> Not doubting it's possible, just curious.

As I recall, when it was first done a "lazy" routine produced as many
bits of pi as a given argument required, doing gonzo arbitrary
precision arithmetic.

Later, computer-aided analysis based on continued fraction expansions
identified the worst possible case across all IEEE doubles (&
singles).  For example, it's possible in reasonable time to find the
IEEE double that comes closest to being an exact integer multiple of
pi/4 (or whatever other range you want to reduce to).  Then it's only
necessary to precompute pi to as many bits as needed to handle the
worst case.

In practice, falling back to that is necessary only for "large"
arguments, and the usual double-precision numeric tricks suffice for
smaller arguments.

Search the web for "trig argument reduction" for whatever the state of
the art may be today ;-)

For actual code, FDLIBM does "as if infinite precision" trig argument
reduction, using a precomputed number of pi bits sufficient to handle
the worst possible IEEE double case, and is available for free from
NETLIB:

http://www.netlib.org/fdlibm/

The code is likely to be baffling, though, as there's scant
explanation.  Reading a paper or two first would be a huge help.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-22 Thread Kirill Balunov
 I apologize that I get into the discussion. Obviously in some situations
it will be useful to check that a floating-point number is integral, but
from the examples given it is clear that they are very rare. Why the
variant with the inclusion of this functionality into the math module was
not considered at all. If the answer is - consistency upon the numeric
tower - will it go for complex type and what will it mean (there can be two
point of views)?

Is this functionality so often used and practical to be a method of float,
int, ..., and not just to be an auxiliary function?

p.s.: The same thoughts about `as_integer_ratio` discussion.

With kind regards,
-gdg
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-22 Thread Robert Smallshire
In the PR which implements is_integer() for int, the numeric tower, and
Decimal I elected not to implement it for Complex or complex. This was
principally because complex instances, even if they have an integral real
value, are not convertible to int and it seems reasonable to me that any
number for which is_integer() returns True should be convertible to int
successfully, and without loss of information.

  >>> int(complex(2, 0))

  Traceback (most recent call last):

File "", line 1, in 

  TypeError: can't convert complex to int


There could be an argument that a putative complex.is_integral() should
therefore return False, but I expect that would get even less support than
the other suggestions in these threads.

*Robert Smallshire | *Managing Director
*Sixty North* | Applications | Consulting | Training
r...@sixty-north.com | T +47 63 01 04 44 | M +47 924 30 350
http://sixty-north.com

On 22 March 2018 at 10:51, Kirill Balunov  wrote:

> I apologize that I get into the discussion. Obviously in some situations
> it will be useful to check that a floating-point number is integral, but
> from the examples given it is clear that they are very rare. Why the
> variant with the inclusion of this functionality into the math module was
> not considered at all. If the answer is - consistency upon the numeric
> tower - will it go for complex type and what will it mean (there can be two
> point of views)?
>
> Is this functionality so often used and practical to be a method of float,
> int, ..., and not just to be an auxiliary function?
>
> p.s.: The same thoughts about `as_integer_ratio` discussion.
>
> With kind regards,
> -gdg
>
>
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
> rob%40sixty-north.com
>
>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-22 Thread Tim Peters
[Kirill Balunov ]
> I apologize that I get into the discussion. Obviously in some situations it
> will be useful to check that a floating-point number is integral, but from
> the examples given it is clear that they are very rare. Why the variant with
> the inclusion of this functionality into the math module was not considered
> at all.

Nobody here really discussed the history, and I don't know.  The
questions here have been about what to do given that `is_integer` and
`as_integer_ratio` are _already_ advertised (public) methods on some
numeric types.


> If the answer is - consistency upon the numeric tower - will it go
> for complex type and what will it mean (there can be two point of views)?

I haven't seen anyone suggest either method be added to Complex.
There are lots of methods that don't show up in the tower before
hitting Real.  For example, given that Complex doesn't support
__float__, it would be bizarre if it _did_ support as_integer_ratio.


> Is this functionality so often used and practical to be a method of float,
> int, ..., and not just to be an auxiliary function?
>
> p.s.: The same thoughts about `as_integer_ratio` discussion.

I would have added them as functions in the `math` module instead.
perhaps supported by dunder methods (__as_integer_ratio__,
__is_integer__).  But that's not what happened, and whether or not
they have double underscores on each end doesn't really make all that
much difference except to dedicated pedants ;-)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-22 Thread Kirill Balunov
2018-03-22 19:47 GMT+03:00 Tim Peters :

>
> > Is this functionality so often used and practical to be a method of
> float,
> > int, ..., and not just to be an auxiliary function?
> >
> > p.s.: The same thoughts about `as_integer_ratio` discussion.
>
> I would have added them as functions in the `math` module instead.
> perhaps supported by dunder methods (__as_integer_ratio__,
> __is_integer__).  But that's not what happened, and whether or not
> they have double underscores on each end doesn't really make all that
> much difference except to dedicated pedants ;-)
>

Yes, this was my point. In spite of the fact that the pronouncement has
already been made, there may still be an opportunity to influence this
decision. I do not think that this is only a matter of choice, how this
functionality will be accessed through a method or function, in fact these
highly specialized methods heavily pollute the API and open the door for
persistent questions. Given the frequency and  activity of using this
`.is_integer` method the deprecation of this method is unlikely to greatly
affect someone. (for `as_integer_ratio` I think the bar is
higher). Summarizing this thread it seems to me that with deprecation of
`is_integer` method and with addition of `is_integer` function in math
module will make everyone happy:

PROS:

1. Those who do not like this method, and do not want to see it as a
redundant part of `int`, ... will be happy
2. Those who need it will have this functionality through math module
3. Compatible packages do not have to quack louder
4. Cleaner API (no need to add this through numeric tower)
5. Make everyone happy and stop this thread :)

CONS:

1. Backward incompatible change

I do not want to restart this topic, but I think that there is an
opportunity for improvement that can be missed.

With kind regards,
-gdg
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deprecating float.is_integer()

2018-03-22 Thread Tim Peters
[Kirill Balunov ]
> ...
> In spite of the fact that the pronouncement has
> already been made, there may still be an opportunity to influence this
> decision.

That's not really how this works.  Guido has been doing this for
decades, and when he Pronounces he's done with it :-)


> I do not think that this is only a matter of choice, how this
> functionality will be accessed through a method or function, in fact these
> highly specialized methods heavily pollute the API

"Heavily"?  Seems oversold.


> and open the door for persistent questions.

That's a door that can never be closed, no matter what.


> Given the frequency and  activity of using this
> `.is_integer` method the deprecation of this method is unlikely to greatly
> affect someone. (for `as_integer_ratio` I think the bar is higher).
> Summarizing this thread it seems to me that with deprecation of `is_integer`
> method and with addition of `is_integer` function in math module will make
> everyone happy:

Not at all, but that's already been explained.  Deprecation is
_serous_ business:  it's not only the presumably relative handful of
direct users who are directly annoyed, but any number of worldwide web
pages, blogs, books, papers, slides, handouts, message boards ... that
so much as mentioned the now-deprecated feature.  The language
implementation is the tiniest part of what's affected, yet is the
_only_ part we (Python developers) can repair.

Deprecation really requires that something is a security hole that
can't be repaired, impossible to make work as intended, approximately
senseless, or is superseded by a new way to accomplish a thing that's
near-universally agreed to be vastly superior.  Maybe others?
Regardless, they're all "really big deals".

The "harm" done by keeping these methods seems approximately
insignificant.  Serhiy certainly found examples where uses made no
good sense, but that's _common_ among floating-point features.  For
example, here's a near-useless implementation of Newton's method for
computing square roots:

def mysqrt(x):
guess = x / 2.0
while guess ** 2 != x:
guess = (guess + x / guess) / 2.0
return guess

And here I'll use it:

>>> mysqrt(25.0)
5.0
>>> mysqrt(25.2)
5.019960159204453

Works great!  Ship it :-)

>>> mysqrt(25.1)

Oops.  It just sits there, consuming cycles.

That's because there is no IEEE double x such that x*x == 25.1.  While
that's not at all obvious, it's true.  Some people really have argued
to deprecate (in)equality testing of floats because of "things like
that", but that's fundamentally nuts.  We may as well remove floats
entirely then.

In short, that an fp feature can be misused, and _is_ misused, is no
argument for deprecating it.  If it can _only_ be misused, that's
different, but that doesn't apply to is_integer.

That someone - or even almost everyone - is merely annoyed by seeing
an API they have no personal use for doesn't get close to "really big
deal".  The time to stop it was before it was added.


> PROS:
> ...
> 5. Make everyone happy and stop this thread :)

This thread ended before you replied to it - I'm just a ghost haunting
its graveyard to keep you from feeling ignored  -)
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com