I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

It would be equivalent to `float('inf')`, i.e. a floating point value representing a non-fininte value. It would be the positive constant; negative infinity could retrieved via `-Infinity`

Or, to keep float representation the same, the name `inf` could be used, but that does not fit Python's normal choice for such identifiers (but indeed, this is what C uses which is the desired behavior of string conversion)

I think there are a number of good reasons for this constant. For example: * It is also a fundamental constant (similar to True, False, and None), and should be representable as such in the language * Requiring a cast from float to string is messy, and also obviously less efficient (but this performance difference is likely insignificant) * Further, having a function call for something that should be a constant is a code-smell; in general str -> float conversion may throw an error or anything else and I'd rather not worry about that. * It would make the useful property that `eval(repr(x)) == x` for floating point numbers (currently, `NameError: name 'inf' is not defined`)

This makes it difficult to, for example, naively serialize a list of floats. For example:

```

x = [1, 2, 3, 4] repr(x)

'[1, 2, 3, 4]'

eval(repr(x)) == x

True

x = [1, 2, 3, float('inf')] repr(x)

'[1, 2, 3, inf]'

eval(repr(x)) == x

Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'inf' is not defined ```

To me, this is problematic; I would expect it to work seamlessly as it does with other floating point constants.

A few rebuttals/claims against: - Creating a new constant (Infinity) which is unassignable may break existing code - Converting a float to string is not the same as it is in C. Whil

I also realize that there is `math.inf`, but I argue that the constant is more fundamental than that, and it still doesn't solve the problem with `repr()` I described

Thanks, ---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

This is in the math module already, along with NaN:

In [1]: import math

In [2]: math.inf

Out[2]: inf

In [3]: math.nan

Out[3]: nan

The same value

In [4]: math.inf == float('inf')

Out[4]: True

but not the same object -- i.e. it's not a singleton.

In [5]: math.inf is float('inf')

Out[5]: False

-CHB

On Fri, Sep 4, 2020 at 9:49 AM Cade Brown brown.cade@gmail.com wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

It would be equivalent to `float('inf')`, i.e. a floating point value representing a non-fininte value. It would be the positive constant; negative infinity could retrieved via `-Infinity`

Or, to keep float representation the same, the name `inf` could be used, but that does not fit Python's normal choice for such identifiers (but indeed, this is what C uses which is the desired behavior of string conversion)

I think there are a number of good reasons for this constant. For example:

- It is also a fundamental constant (similar to True, False, and None),
and should be representable as such in the language

- Requiring a cast from float to string is messy, and also obviously
less efficient (but this performance difference is likely insignificant) * Further, having a function call for something that should be a constant is a code-smell; in general str -> float conversion may throw an error or anything else and I'd rather not worry about that.

- It would make the useful property that `eval(repr(x)) == x` for
floating point numbers (currently, `NameError: name 'inf' is not defined`)

This makes it difficult to, for example, naively serialize a list of floats. For example:

`>>> x = [1, 2, 3, 4] >>> repr(x) '[1, 2, 3, 4]' >>> eval(repr(x)) == x True >>> x = [1, 2, 3, float('inf')] >>> repr(x) '[1, 2, 3, inf]' >>> eval(repr(x)) == x Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'inf' is not defined`

To me, this is problematic; I would expect it to work seamlessly as it does with other floating point constants.

A few rebuttals/claims against:

- Creating a new constant (Infinity) which is unassignable may break
existing code

- Converting a float to string is not the same as it is in C. Whil
I also realize that there is `math.inf`, but I argue that the constant is more fundamental than that, and it still doesn't solve the problem with `repr()` I described

## Thanks,

*Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/XMA6KO... Code of Conduct: http://python.org/psf/codeofconduct/

I mentioned that in my post; however it doesn't satisfy the problems I have (mainly being that eval(repr(x))==x)

I still think unifying it as a constant is better because then the repr of a float gives a string which, if evaluated, gives the float back exactly. Using math.inf or string conversion throws an error if you try to evaluate it

On Fri, Sep 4, 2020, 6:05 PM Christopher Barker pythonchb@gmail.com wrote:

This is in the math module already, along with NaN:

In [1]: import math

In [2]: math.inf

Out[2]: inf

In [3]: math.nan

Out[3]: nan

The same value

In [4]: math.inf == float('inf')

Out[4]: True

but not the same object -- i.e. it's not a singleton.

In [5]: math.inf is float('inf')

Out[5]: False

-CHB

On Fri, Sep 4, 2020 at 9:49 AM Cade Brown brown.cade@gmail.com wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

It would be equivalent to `float('inf')`, i.e. a floating point value representing a non-fininte value. It would be the positive constant; negative infinity could retrieved via `-Infinity`

Or, to keep float representation the same, the name `inf` could be used, but that does not fit Python's normal choice for such identifiers (but indeed, this is what C uses which is the desired behavior of string conversion)

I think there are a number of good reasons for this constant. For example:

- It is also a fundamental constant (similar to True, False, and None),
and should be representable as such in the language

- Requiring a cast from float to string is messy, and also obviously
less efficient (but this performance difference is likely insignificant) * Further, having a function call for something that should be a constant is a code-smell; in general str -> float conversion may throw an error or anything else and I'd rather not worry about that.

- It would make the useful property that `eval(repr(x)) == x` for
floating point numbers (currently, `NameError: name 'inf' is not defined `)

This makes it difficult to, for example, naively serialize a list of floats. For example:

`>>> x = [1, 2, 3, 4] >>> repr(x) '[1, 2, 3, 4]' >>> eval(repr(x)) == x True >>> x = [1, 2, 3, float('inf')] >>> repr(x) '[1, 2, 3, inf]' >>> eval(repr(x)) == x Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'inf' is not defined`

To me, this is problematic; I would expect it to work seamlessly as it does with other floating point constants.

A few rebuttals/claims against:

- Creating a new constant (Infinity) which is unassignable may break
existing code

- Converting a float to string is not the same as it is in C. Whil
I also realize that there is `math.inf`, but I argue that the constant is more fundamental than that, and it still doesn't solve the problem with `repr()` I described

## Thanks,

*Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/XMA6KO... Code of Conduct: http://python.org/psf/codeofconduct/

-- Christopher Barker, PhD

Python Language Consulting

- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

On Sat, Sep 5, 2020 at 8:12 AM Cade Brown brown.cade@gmail.com wrote:

I mentioned that in my post; however it doesn't satisfy the problems I have (mainly being that eval(repr(x))==x)

I still think unifying it as a constant is better because then the repr of a float gives a string which, if evaluated, gives the float back exactly. Using math.inf or string conversion throws an error if you try to evaluate it

Remember that if this matters to you, you can "from math import inf". So your proposal is to, in effect, do this by default. I'm -0 on it because it's so easy to do if you want it.

ChrisA

On 5/09/20 10:15 am, Chris Angelico wrote:

Remember that if this matters to you, you can "from math import inf".

But you still need to use full eval on your repr, which could be a serious security problem in some contexts. If it were a built-in constant, ast.literal_eval could be used instead.

On Sat, Sep 5, 2020 at 8:45 AM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 5/09/20 10:15 am, Chris Angelico wrote:

Remember that if this matters to you, you can "from math import inf".

But you still need to use full eval on your repr, which could be a serious security problem in some contexts. If it were a built-in constant, ast.literal_eval could be used instead.

Perhaps the real solution is for literal_eval to be given a specific set of names that it's allowed to reference. Most things don't have to be keywords - it's normally fine for them to be builtins. (Or, in many cases, importables.) If you make "inf" a keyword, then even the Python standard library is broken.

ChrisA

On Sat, Sep 5, 2020 at 11:30 AM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 5/09/20 10:51 am, Chris Angelico wrote:

If you make "inf" a keyword, then even the Python standard library is broken.

The OP didn't suggest that, he suggested adding a new name such as Infinity that reprs could use.

Suggested both, actually. But IMO neither is necessary, both can break stuff, and the value of it is low. Not everything has to be a keyword.

ChrisA

The `eval(repr(x)) == x` is not a segment of my code; rather it is part of Python's description of what 'repr' should do:

https://docs.python.org/3.4/library/functions.html?highlight=repr#repr

Specifically: ` For many types, this function makes an attempt to return a string that would yield an object with the same value when passed to eval()` https://docs.python.org/3.4/library/functions.html?highlight=repr#eval

So everyone in this thread can stop mentioning security concerns; I'm sure we're all aware of those and we should instead focus on what repr should do and shouldn't do.

I think it's weird to not fulfill this promise, when it should be easy to do. Further, I agree that 'inf' is: 1. Too backwards incompatible 2. Not the right format for Python (Python likes pascalcase, like `None`, `True`, `False`)

So again, I'd like to not focus on arguing whether a particular codebase should be using 'eval' on strings generated by repr. Rather, my point was that the current behavior does not follow what Python suggests and says 'repr' should do.

---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

On Fri, Sep 4, 2020 at 9:31 PM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 5/09/20 10:51 am, Chris Angelico wrote:

If you make "inf" a keyword, then even the Python standard library is broken.

The OP didn't suggest that, he suggested adding a new name such as Infinity that reprs could use.

-- Greg _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TTFTEB... Code of Conduct: http://python.org/psf/codeofconduct/

On Fri, Sep 04, 2020 at 09:40:55PM -0400, Cade Brown wrote:

The `eval(repr(x)) == x` is not a segment of my code; rather it is part of Python's description of what 'repr' should do:

https://docs.python.org/3.4/library/functions.html?highlight=repr#repr

Specifically: ` For many types, this function makes an attempt to return a string that would yield an object with the same value when passed to eval()` https://docs.python.org/3.4/library/functions.html?highlight=repr#eval

"For many types" and "makes an attempt".

There has never been, and never will be, a guarantee that all objects will obey that invariant. As I said, it is a Nice To Have, and it is designed for convenience at the interactive interpreter.

So everyone in this thread can stop mentioning security concerns; I'm sure we're all aware of those and we should instead focus on what repr should do and shouldn't do.

You specifically said that math.inf doesn't solve your problem *because* `eval(repr(x))` doesn't work. Now you are backpeddling and saying that this is not your actual problem.

(In fact it does work, if you do it correctly.)

There are a million other objects that don't obey that invariant:

py> x = object() py> eval(repr(x)) == x SyntaxError: invalid syntax

Why is float infinity so special that it needs to obey the invariant?

What's the actual problem, or problems, in your code that you are trying to solve by making an infinity builtin? If there is no actual problem being solved, and the only reason you want this is because:

I think it's weird to not fulfill this promise

you don't have any sympathy from me:

- `eval(repr(x))` is not a promise, it is a mere suggestion that *some* types *try* to provide.

- Adding a special built-in constant Infinity just to satisfy this Nice To Have feature is overkill.

- It would require float infinities to change their repr from 'inf' to 'Infinity', and that will break doctests.

- And even if that feature were satisfied by infinity, it couldn't be satisfied by float NANs by their very definition:

py> from math import nan py> nan == nan False

So while the cost of adding a new Infinity builtin is small, the benefit is even smaller.

I am a -0 on this, but I think it was Greg Ewing that presented a real use case:

There is no way to use literal_eval that gets you an inf (or NaN value).

Which is a real, though maybe not important, use case.

-CHB

On Fri, Sep 4, 2020 at 7:15 PM Steven D'Aprano steve@pearwood.info wrote:

On Fri, Sep 04, 2020 at 09:40:55PM -0400, Cade Brown wrote:

The `eval(repr(x)) == x` is not a segment of my code; rather it is part

of

Python's description of what 'repr' should do:

https://docs.python.org/3.4/library/functions.html?highlight=repr#repr

Specifically: ` For many types, this function makes an attempt to return

a

string that would yield an object with the same value when passed to

eval()`

https://docs.python.org/3.4/library/functions.html?highlight=repr#eval

"For many types" and "makes an attempt".

There has never been, and never will be, a guarantee that all objects

will obey that invariant. As I said, it is a Nice To Have, and it is

designed for convenience at the interactive interpreter.

So everyone in this thread can stop mentioning security concerns; I'm

sure

we're all aware of those and we should instead focus on what repr should

do

and shouldn't do.

You specifically said that math.inf doesn't solve your problem *because*

`eval(repr(x))` doesn't work. Now you are backpeddling and saying that

this is not your actual problem.

(In fact it does work, if you do it correctly.)

There are a million other objects that don't obey that invariant:

`py> x = object() py> eval(repr(x)) == x SyntaxError: invalid syntax`

Why is float infinity so special that it needs to obey the

invariant?

What's the actual problem, or problems, in your code that you are trying

to solve by making an infinity builtin? If there is no actual problem

being solved, and the only reason you want this is because:

I think it's weird to not fulfill this promise

you don't have any sympathy from me:

`eval(repr(x))` is not a promise, it is a mere suggestion

that *some* types *try* to provide.

Adding a special built-in constant Infinity just to satisfy

this Nice To Have feature is overkill.

It would require float infinities to change their repr from

'inf' to 'Infinity', and that will break doctests.

And even if that feature were satisfied by infinity, it

couldn't be satisfied by float NANs by their very definition:

py> from math import nan

py> nan == nan

False

So while the cost of adding a new Infinity builtin is small, the benefit

is even smaller.

--

Steve

Python-ideas mailing list -- python-ideas@python.org

To unsubscribe send an email to python-ideas-leave@python.org

https://mail.python.org/mailman3/lists/python-ideas.python.org/

Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/AHJETD...

Code of Conduct: http://python.org/psf/codeofconduct/

--

Christopher Barker, PhD

Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Fri, Sep 04, 2020 at 08:52:22PM -0700, Christopher Barker wrote:

I am a -0 on this, but I think it was Greg Ewing that presented a real use case:

There is no way to use literal_eval that gets you an inf (or NaN value).

Which is a real, though maybe not important, use case.

That's not a *use-case*. A use-case is practical problem you are trying to solve.

Without a use-case for why you need literal_value to return an inf, that's merely an observation, no different from the observation that there is no way to use zip or list to get an inf. It's true, but so what?

That's not a rhetorical question. It might be that there is a good use-case for using literal_eval and needing to generate infinities.

But there are many objects that you can't construct with literal_eval. Because they aren't literals, or even semi-literals like tuple displays and complex numbers. It's not clear to me that we should care about infs and NANs in literal_eval.

But if we should care, making inf (and NAN?) a builtin constant is probably not the best solution.

On Sat, Sep 05, 2020 at 11:01:33AM +0300, Serhiy Storchaka wrote:

05.09.20 06:52, Christopher Barker пише:

I am a -0 on this, but I think it was Greg Ewing that presented a real use case:

There is no way to use literal_eval that gets you an inf (or NaN value).

ast.literal_eval('1e1000')

I don't think that's a language guarantee though. It should work in Python interpreters that have IEEE-754 floats (the majority of platforms), but I wouldn't expect it to work everywhere.

Does it work in MicroPython on small systems?

First of all, you're comparing immutable value types to dynamic objects which are predicated and processed based on the memory address (e.g. for equality testing, by default). Of course they're going to have different semantics, especially when converting to a unique string representation. A better question to ask is why does it work for *almost* all values of 'float' , but not infinite ones... This is a glaring hole in my opinion.

Why do you think having 'inf' is better than something that means something to the python interpreter? I've had countless times where I've had to Google how to create an infinite float, and second guessed myself because it is very unintuitive to have to call a string conversion to get what amounts to a constant.

The 'use case' is being able to specify a number which is constant, by a constant, and not requiring me to execute a function call. Further, keeping it the way it is harbors readability. Every time I parse code that contains `float('inf')` I ask myself why it is having to do this, because it seems like code shouldn't have to.

Your argument seems to stem from the least possible Python can do (i.e. it doesn't HAVE to do anything more than it does currently). This mailing list is python-ideas, which is for ideas currently not in Python. I am aware that nothing *has* to be done, I am merely suggesting why it would make sense to add, and why it would make Python a more complete, predictable and frankly 'prettier' language (albeit subjective). I don't see how any of your points address those concerns

On Fri, Sep 4, 2020, 10:14 PM Steven D'Aprano steve@pearwood.info wrote:

On Fri, Sep 04, 2020 at 09:40:55PM -0400, Cade Brown wrote:

The `eval(repr(x)) == x` is not a segment of my code; rather it is part

of

Python's description of what 'repr' should do:

https://docs.python.org/3.4/library/functions.html?highlight=repr#repr

Specifically: ` For many types, this function makes an attempt to return

a

string that would yield an object with the same value when passed to

eval()`

https://docs.python.org/3.4/library/functions.html?highlight=repr#eval

"For many types" and "makes an attempt".

There has never been, and never will be, a guarantee that all objects will obey that invariant. As I said, it is a Nice To Have, and it is designed for convenience at the interactive interpreter.

So everyone in this thread can stop mentioning security concerns; I'm

sure

we're all aware of those and we should instead focus on what repr should

do

and shouldn't do.

You specifically said that math.inf doesn't solve your problem *because* `eval(repr(x))` doesn't work. Now you are backpeddling and saying that this is not your actual problem.

(In fact it does work, if you do it correctly.)

There are a million other objects that don't obey that invariant:

`py> x = object() py> eval(repr(x)) == x SyntaxError: invalid syntax`

Why is float infinity so special that it needs to obey the invariant?

What's the actual problem, or problems, in your code that you are trying to solve by making an infinity builtin? If there is no actual problem being solved, and the only reason you want this is because:

I think it's weird to not fulfill this promise

you don't have any sympathy from me:

`eval(repr(x))` is not a promise, it is a mere suggestion that *some* types *try* to provide.

Adding a special built-in constant Infinity just to satisfy this Nice To Have feature is overkill.

It would require float infinities to change their repr from 'inf' to 'Infinity', and that will break doctests.

And even if that feature were satisfied by infinity, it couldn't be satisfied by float NANs by their very definition:

py> from math import nan py> nan == nan False

So while the cost of adding a new Infinity builtin is small, the benefit is even smaller.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/AHJETD... Code of Conduct: http://python.org/psf/codeofconduct/

Also, I've seen multiple people say I suggested 'inf' as the name when I've specifically said at least twice that it would not be my choice for the identifier. I clearly have said 'Infinity' is the far superior choice for Python. My comments were that currently, Python displays 'inf' as the string representation, and that the repr function would be changed to return the new identifier (i.e. `repr(float('inf')) == 'Infinity'`)

And, I am undecided on 'nan' semantics (`NaN` would be my choice of identifier, in any situation), since it is (by definition) not a number. It's kind of odd that Python has it, especially since it has 'none'. I guess it's good for interfacing with C APIs and lower level functions that require a float and not a generic object, but I digress. In any case, it would be very similar to 'Infinity' constants (some differences: `float('nan') is float('nan')` is False, whereas `NaN is NaN` would be True, but of course `NaN == NaN` is still False)

Thanks, ---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

On Sat, Sep 5, 2020 at 12:44 AM Cade Brown brown.cade@gmail.com wrote:

First of all, you're comparing immutable value types to dynamic objects which are predicated and processed based on the memory address (e.g. for equality testing, by default). Of course they're going to have different semantics, especially when converting to a unique string representation. A better question to ask is why does it work for *almost* all values of 'float' , but not infinite ones... This is a glaring hole in my opinion.

Why do you think having 'inf' is better than something that means something to the python interpreter? I've had countless times where I've had to Google how to create an infinite float, and second guessed myself because it is very unintuitive to have to call a string conversion to get what amounts to a constant.

The 'use case' is being able to specify a number which is constant, by a constant, and not requiring me to execute a function call. Further, keeping it the way it is harbors readability. Every time I parse code that contains `float('inf')` I ask myself why it is having to do this, because it seems like code shouldn't have to.

Your argument seems to stem from the least possible Python can do (i.e. it doesn't HAVE to do anything more than it does currently). This mailing list is python-ideas, which is for ideas currently not in Python. I am aware that nothing *has* to be done, I am merely suggesting why it would make sense to add, and why it would make Python a more complete, predictable and frankly 'prettier' language (albeit subjective). I don't see how any of your points address those concerns

On Fri, Sep 4, 2020, 10:14 PM Steven D'Aprano steve@pearwood.info wrote:

On Fri, Sep 04, 2020 at 09:40:55PM -0400, Cade Brown wrote:

The `eval(repr(x)) == x` is not a segment of my code; rather it is part

of

Python's description of what 'repr' should do:

https://docs.python.org/3.4/library/functions.html?highlight=repr#repr

Specifically: ` For many types, this function makes an attempt to

return a

string that would yield an object with the same value when passed to

eval()`

<https://docs.python.org/3.4/library/functions.html?highlight=repr#eval

"For many types" and "makes an attempt".

There has never been, and never will be, a guarantee that all objects will obey that invariant. As I said, it is a Nice To Have, and it is designed for convenience at the interactive interpreter.

So everyone in this thread can stop mentioning security concerns; I'm

sure

we're all aware of those and we should instead focus on what repr

should do

and shouldn't do.

You specifically said that math.inf doesn't solve your problem *because* `eval(repr(x))` doesn't work. Now you are backpeddling and saying that this is not your actual problem.

(In fact it does work, if you do it correctly.)

There are a million other objects that don't obey that invariant:

`py> x = object() py> eval(repr(x)) == x SyntaxError: invalid syntax`

Why is float infinity so special that it needs to obey the invariant?

What's the actual problem, or problems, in your code that you are trying to solve by making an infinity builtin? If there is no actual problem being solved, and the only reason you want this is because:

I think it's weird to not fulfill this promise

you don't have any sympathy from me:

`eval(repr(x))` is not a promise, it is a mere suggestion that *some* types *try* to provide.

Adding a special built-in constant Infinity just to satisfy this Nice To Have feature is overkill.

It would require float infinities to change their repr from 'inf' to 'Infinity', and that will break doctests.

And even if that feature were satisfied by infinity, it couldn't be satisfied by float NANs by their very definition:

py> from math import nan py> nan == nan False

So while the cost of adding a new Infinity builtin is small, the benefit is even smaller.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/AHJETD... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 05, 2020 at 12:44:47AM -0400, Cade Brown wrote:

First of all, you're comparing immutable value types to dynamic objects which are predicated and processed based on the memory address (e.g. for equality testing, by default). Of course they're going to have different semantics, especially when converting to a unique string representation.

Um, yes?

What's your point here? There is no guarantee that `eval(repr(x))` must always return something equal to x, and one reason that isn't a guarantee is the difference between value types (whether mutable or not) and identity types. That's not the only acceptable reason though.

A better question to ask is why does it work for *almost* all values of 'float' , but not infinite ones... This is a glaring hole in my opinion.

That is a better question, but it's not a great question. Nor is it a glaring hole: Python is 30 years old, if this was an obvious lack that people need regularly, it would have been fixed years ago.

Unless you have thought of something new that none of the tens or hundreds of thousands of Python users over the decades have thought of, I think we can be fairly confident that this is at best a minor feature.

Python is a mature and popular language. Any "glaring hole" in the language is likely to be:

- a matter of personal preference or taste;

- something that has been ruled out due to backwards compatibility or because it doesn't fit the execution model;

- or something of such minor importance that nobody noticed or cared.

In the last case, it's not exactly *glaring* then.

Why do you think having 'inf' is better than something that means something to the python interpreter?

Not everything has to be a builtin constant.

If it's a keyword, there is the *very large* cost that it will break any code that uses Infinity as a name.

There's the opportunity cost: once we create an Infinity or Inf constant, then we're stuck with it forever, even if a better use for that name comes along.

There is the development cost: somebody has to do the work, write the tests, write the documentation.

There's the on-going bloating cost: every new feature increases the size of the language, the interpreter, the documentation, the time it takes to compile the interpreter, etc. A few milliseconds here, a few bytes there, it all adds up.

There's the cost to users: one more builtin that you have to learn, one more thing to know, one more choice to make, more questions for beginners to ask:

"What's the difference between float('inf') and Infinity?"

"Why is it Infinity not Inf?"

"Why is there no builtin NAN constant?"

You can argue that these are all *small* costs, and I agree. (Other than the backwards-compatibility breaking use of a new keyword, which alone would almost certainly rule this out.)

But, based on the discussion so far, the benefit is even smaller. If the costs are greater than the benefit, then adding an Infinity constant will make the language worse, not better.

Come up with an important, interesting use-case, and that balance could change. But consistency with other floats alone is not a very interesting or important reason.

There's no NAN constant either. Do you want that?

I've had countless times where I've had to Google how to create an infinite float, and second guessed myself because it is very unintuitive to have to call a string conversion to get what amounts to a constant.

x = Decimal('0.1') p = Path('/home/user/file') regex = re.compile(r'spam.*')

Does this mean that we need to have constants for Decimals, Paths, regexes, etc too?

I guess we need an infinite number of builtin named constants.

No? Then what makes infinity important enough to be an exception?

I'm sorry that you can't remember the basic idiom `float('inf')` or that you can import it from the math lib, even after googling it "countless" times. Perhaps you should write it on a postit note and stick it on your monitor?

I'm not being sarcastic. I've literally done that for other things I had trouble remembering.

The 'use case' is being able to specify a number which is constant, by a constant, and not requiring me to execute a function call.

That's not a use-case. That's a personal preference that literally boils down to "But I don't want to use a function call!".

But okay, you can get this by monkey-patching the builtins. Stick this in your PYTHONSTARTUP file, or the entry point to your Python applications:

import builtins builtins.inf = float('inf')

and now you can use `inf` as a builtin name everywhere.

It's not a keyword, but making Infinity a keyword would be even more costly, breaking backwards compatibility for very little benefit.

Further, keeping it the way it is harbors readability. Every time I parse code that contains `float('inf')` I ask myself why it is having to do this, because it seems like code shouldn't have to.

I think you mean "hinders", and I think that's a very idiosyncratic complaint. I think more people would be confused why Python makes Infinity a special built-in constant. C and Java don't.

On the other hand, Javascript and Julia do. So maybe you can find the rationale they used for adding them, and if it applies here, Python may do the same.

Your argument seems to stem from the least possible Python can do (i.e. it doesn't HAVE to do anything more than it does currently).

Correct!

This mailing list is python-ideas, which is for ideas currently not in Python. I am aware that nothing *has* to be done, I am merely suggesting why it would make sense to add, and why it would make Python a more complete, predictable and frankly 'prettier' language (albeit subjective). I don't see how any of your points address those concerns

Nobody is saying you are in the wrong for raising the issue. Only that you haven't given sufficient justification for this to go through the stages:

* an idea

* a good idea

* a good idea with consensus that we should do it

* somebody actually does the work to make it happen.

The truth is, for my own petty and personal reasons, I wish Python had INF and NAN builtins too. My own PYTHONSTARTUP file contains code to add them to the main namespace (I don't bother with putting them in builtins, because I only use them interactively). But I'm pretty sure I would be in a minority for that.

And that's the point of this list really. It's not about "What's best for *me*?" it's "What's best for the majority?"

It might help if you read this blog post by one of the senior devs:

https://www.curiousefficiency.org/posts/2011/02/status-quo-wins-stalemate.ht...

I don't think that anyone disagrees that there are advantages to having a builtin Infinity. Only whether the advantages outweigh the costs and disadvantages.

On Sat, Sep 5, 2020 at 12:43 AM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 5/09/20 10:15 am, Chris Angelico wrote:

Remember that if this matters to you, you can "from math import inf".

But you still need to use full eval on your repr, which could be a serious security problem in some contexts. If it were a built-in constant, ast.literal_eval could be used instead.

In most such cases you could use Python's json module which supports Infinity.

05.09.20 01:43, Greg Ewing пише:

On 5/09/20 10:15 am, Chris Angelico wrote:

Remember that if this matters to you, you can "from math import inf".

It is better to use float() instead of ast.literal_eval(). ast.literal_eval() is not a "safe eval", it can crash the interpreter or use enormous CPU time. It can be used to organize DOS attacks.

On Fri, 4 Sep 2020 at 19:12, Cade Brown brown.cade@gmail.com wrote:

I mentioned that in my post; however it doesn't satisfy the problems I have (mainly being that eval(repr(x))==x)

In [1]: from math import inf

In [2]: eval(repr(inf)) == inf

Out[2]: True

"works for me"

I still think unifying it as a constant is better because then the repr of a float gives a string which, if evaluated, gives the float back exactly. Using math.inf or string conversion throws an error if you try to evaluate it

On Fri, Sep 4, 2020, 6:05 PM Christopher Barker pythonchb@gmail.com wrote:

This is in the math module already, along with NaN:

In [1]: import math

In [2]: math.inf

Out[2]: inf

In [3]: math.nan

Out[3]: nan

The same value

In [4]: math.inf == float('inf')

Out[4]: True

but not the same object -- i.e. it's not a singleton.

In [5]: math.inf is float('inf')

Out[5]: False

-CHB

On Fri, Sep 4, 2020 at 9:49 AM Cade Brown brown.cade@gmail.com wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

I think there are a number of good reasons for this constant. For example:

- It is also a fundamental constant (similar to True, False, and
None), and should be representable as such in the language

- Requiring a cast from float to string is messy, and also obviously
less efficient (but this performance difference is likely insignificant) * Further, having a function call for something that should be a constant is a code-smell; in general str -> float conversion may throw an error or anything else and I'd rather not worry about that.

- It would make the useful property that `eval(repr(x)) == x` for
floating point numbers (currently, `NameError: name 'inf' is not defined `)

This makes it difficult to, for example, naively serialize a list of floats. For example:

`>>> x = [1, 2, 3, 4] >>> repr(x) '[1, 2, 3, 4]' >>> eval(repr(x)) == x True >>> x = [1, 2, 3, float('inf')] >>> repr(x) '[1, 2, 3, inf]' >>> eval(repr(x)) == x Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'inf' is not defined`

A few rebuttals/claims against:

- Creating a new constant (Infinity) which is unassignable may break
existing code

- Converting a float to string is not the same as it is in C. Whil
## Thanks,

*Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/XMA6KO... Code of Conduct: http://python.org/psf/codeofconduct/

-- Christopher Barker, PhD

Python Language Consulting

- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/QHOV45... Code of Conduct: http://python.org/psf/codeofconduct/

On Fri, Sep 04, 2020 at 06:10:23PM -0400, Cade Brown wrote:

I'm not very sympathetic to that problem. `eval(repr(x))` is a Nice To Have convenience for the interactive interpreter, it is not a guarantee, and it is not best practice when coding -- especially not if your x values are objects that come from a third party.

`float(repr(x))` works fine and avoids both the security and performance issues with eval:

py> from math import inf py> nums = [1.2, -8.9e-50, inf] py> all([float(repr(x)) == x for x in nums]) True

So I'm going to climb out on a limb here and say that if you're calling eval on the repr of floats, you're probably doing the wrong thing. In fact, if you know that they are certainly floats, and never any other kind of object, then you are *certainly* doing the wrong thing because of performance:

$ python3 -m timeit "eval('1.2575')" 100000 loops, best of 5: 3.21 usec per loop $ python3 -m timeit "float('1.2575')" 2000000 loops, best of 5: 113 nsec per loop

And if you *don't* know what sort of objects they are, then you're leaving yourself open to a world of hurt if there is any possibility you might get them from an untrusted third-party.

On Fri, Sep 04, 2020 at 06:10:23PM -0400, Cade Brown wrote:

Further to my previous comment, if you *absolutely must* use eval, you can mitigate some (but not all) security threats and solve your eval(repr) issue:

# evaluate string `s` a little bit less dangerously if '_' in s: raise ValueError('underscore prohibited') else: eval(s, {'inf': math.inf, '__builtins__': None})

On Sat, Sep 5, 2020 at 10:11 AM Steven D'Aprano steve@pearwood.info wrote:

On Fri, Sep 04, 2020 at 06:10:23PM -0400, Cade Brown wrote:

Further to my previous comment, if you *absolutely must* use eval, you can mitigate some (but not all) security threats and solve your eval(repr) issue:

`# evaluate string `s` a little bit less dangerously if '_' in s: raise ValueError('underscore prohibited') else: eval(s, {'inf': math.inf, '__builtins__': None})`

But don't expect that to actually be secure. It mitigates SOME security threats.

I think Python would do very well to have a "restricted evaluation" function. Looking at the source code for literal_eval, it doesn't seem too hard to add a check alongside the Constant handler to say "if it's Name, context Load, look up the name in the provided dict".

ChrisA

05.09.20 03:24, Chris Angelico пише:

But don't expect that to actually be secure. It mitigates SOME security threats.

I think Python would do very well to have a "restricted evaluation" function. Looking at the source code for literal_eval, it doesn't seem too hard to add a check alongside the Constant handler to say "if it's Name, context Load, look up the name in the provided dict".

It is more hard that you think. Try ast.literal_eval('+1'*1000000). It crashes before you start to walk the AST tree.

You need to implement at least your own AST parser in pure Python to make more safe eval. And there are other vectors of attack (for example via string-to-integer converter).

On Fri, Sep 4, 2020, 12:48 Cade Brown brown.cade@gmail.com wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

I think there are a number of good reasons for this constant. For example:

- It is also a fundamental constant (similar to True, False, and None),
and should be representable as such in the language

- Requiring a cast from float to string is messy, and also obviously

- It would make the useful property that `eval(repr(x)) == x` for
floating point numbers (currently, `NameError: name 'inf' is not defined`)

This makes it difficult to, for example, naively serialize a list of floats. For example:

A few rebuttals/claims against:

- Creating a new constant (Infinity) which is unassignable may break
existing code

It will break an ENORMOUS amount of code. Numpy has its own top-level "inf" variable. So all code that uses "from numpy import *" will break. Pylab imports numpy in that way, so "from pylab import *" will also break. Whether you think this is a good approach or not, a ton of tutorials recommend doing this. All of those tutorials will break in a way that is very hard to fix.

"from foo import *" is a really lazy programming practice that assumes there are no symbol clashes between the module's namespace and the current namespace. It makes production code harder to maintain because the reader has to figure out whether a given function or class name is defined in the current namespace or merely mapped there from another module for convenience.

I know it is common in tutorials (especially C++ tutorials mapping 'std' into global) to make example code shorter and somehow easier to read (especially in books). Unfortunately, the reason namespaces exist is rarely emphasized, which gives the impression that it is a common acceptable practice. Everyplace I have worked has had the hard rule that modules are never mapped into the global namespace in production code (for both C++ and Python).

Restricting symbols in the global namespace to prevent clashes in module namespaces seems like backward reasoning to accommodate bad practices. The fact that pylab takes care to allow mapping all of the numpy symbols into its namespace to make pylab a super namespace of the two has nothing to do with mapping the symbols into the global namespace.

//Jeff

On 9/4/20 3:30 PM, Todd wrote:

On Fri, Sep 4, 2020, 12:48 Cade Brown <brown.cade@gmail.com mailto:brown.cade@gmail.com> wrote:

`I am positing that Python should contain a constant (similar to True, False, None), called Infinity. It would be equivalent to `float('inf')`, i.e. a floating point value representing a non-fininte value. It would be the positive constant; negative infinity could retrieved via `-Infinity` Or, to keep float representation the same, the name `inf` could be used, but that does not fit Python's normal choice for such identifiers (but indeed, this is what C uses which is the desired behavior of string conversion) I think there are a number of good reasons for this constant. For example: * It is also a fundamental constant (similar to True, False, and None), and should be representable as such in the language * Requiring a cast from float to string is messy, and also obviously less efficient (but this performance difference is likely insignificant) * Further, having a function call for something that should be a constant is a code-smell; in general str -> float conversion may throw an error or anything else and I'd rather not worry about that. * It would make the useful property that `eval(repr(x)) == x` for floating point numbers (currently, `NameError: name 'inf' is not defined`) This makes it difficult to, for example, naively serialize a list of floats. For example: ``` >>> x = [1, 2, 3, 4] >>> repr(x) '[1, 2, 3, 4]' >>> eval(repr(x)) == x True >>> x = [1, 2, 3, float('inf')] >>> repr(x) '[1, 2, 3, inf]' >>> eval(repr(x)) == x Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'inf' is not defined ``` To me, this is problematic; I would expect it to work seamlessly as it does with other floating point constants. A few rebuttals/claims against: - Creating a new constant (Infinity) which is unassignable may break existing code`

It will break an ENORMOUS amount of code. Numpy has its own top-level "inf" variable. So all code that uses "from numpy import *" will break. Pylab imports numpy in that way, so "from pylab import *" will also break. Whether you think this is a good approach or not, a ton of tutorials recommend doing this. All of those tutorials will break in a way that is very hard to fix.

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GTPEHR... Code of Conduct: http://python.org/psf/codeofconduct/

Jeffrey Kintscher writes:

"from foo import *" is a really lazy programming practice

However much corporate policies and educators may deprecate widely adopted coding practices, complaining about them will get you disliked, and nothing else.

If you want an Infinity constant adopted, please tell us why this has such huge benefits as opposed to the spelling "float('inf')". See Cade Brown's posts, you don't need to (and shouldn't) repeat them. I find them unpersuasive; I see the point, but I don't think they overcomes the principle that this is a relatively rarely used facility, and so doesn't need to be built-in.

Also someone needs to explain how to avoid the debacle that was the the name collisions with True and False when the bool type was introduced.

On 9/5/20 12:00 AM, Stephen J. Turnbull wrote:

Jeffrey Kintscher writes:

"from foo import *" is a really lazy programming practice

However much corporate policies and educators may deprecate widely adopted coding practices, complaining about them will get you disliked, and nothing else.

I could say the same thing about people who make disparaging comments in mailing lists.

My point was that importing "everything" into the global namespace and then finding that a new version of Python has a new global symbol that causes a symbol conflict in your code is not a reason to reject the change. If you use a problematic practice and a change to Python causes a symbol conflict for you, that's on you, not Python.

//Jeff

Jeffrey Kintscher writes:

If you use a problematic practice and a change to Python causes a symbol conflict for you, that's on you, not Python.

You are welcome to think that way. It's not representative of the Python development community, though. We[1] care about breaking existing code, even if we don't think much of it.

Furthermore, "from module import *" is implicitly blessed, not only by that idiom itself (which requires special treatment in the parser!), but also by the existence of the __all__ dunder, which allows module authors to control which identifiers can be imported that way. Given that, evidently not all instances of "from module import *" are problematic, and which are problematic is a matter of taste. The principle of "consenting adults" means that unless we have a good reason, we'd rather avoid breaking *future* code that uses valid syntax.

A fairly tight sufficient condition is "there's no sane way to do it". For example, if Serhiy's "from ast import literal_eval; literal_eval('1e1000')" was the only way to spell infinity, there'd be an overwhelming sense that "we gotta do something." But when we already have two ways ("float('inf')" and "from math import inf; inf") you're gonna get float('inf') pushback instead.

Footnotes: [1] Yeah, I think I can speak for the community on this one.

On 9/5/20 1:18 AM, Jeffrey Kintscher wrote:

My point was that importing "everything" into the global namespace

The only global namespace in Python is builtins [1]. Everything else is module or local.

and then finding that a new version of Python has a new global symbol that causes a symbol conflict in your code is not a reason to reject the change.

Actually, it is. The benefit has to be pretty big to overcome backwards compatibility concerns.

If you use a problematic practice and a change to Python causes a symbol conflict for you, that's on you, not Python.

An officially supported practice that is broken by Python is on Python. Again, the benefits would have to outweigh the code breakage.

-- ~Ethan~

[1] `globals()` actually returns the module namespace.

On Sat, Sep 05, 2020 at 04:00:40PM +0900, Stephen J. Turnbull wrote:

Jeffrey Kintscher writes:

"from foo import *" is a really lazy programming practice

However much corporate policies and educators may deprecate widely adopted coding practices, complaining about them will get you disliked, and nothing else.

*scratches head in confusion*

Since when did `from foo import *` suddenly become a widely adopted coding practice?

Everyone I know agrees that (with very few exceptions) we should avoid star imports. I don't know anyone who argues in favour of star imports in the general case. It is permitted, but not encouraged.

PEP 8 strongly discourages it:

https://www.python.org/dev/peps/pep-0008/#imports

Google bans it, allowing only imports of modules:

https://github.com/google/styleguide/blob/gh-pages/pyguide.md

(Some conditions apply, but nothing that would allow wildcard imports.)

Linters warn about it:

https://www.flake8rules.com/rules/F403.html

The community seems to be in agreement that, for the most part, wildcard imports should be avoided, e.g.

https://www.geeksforgeeks.org/why-import-star-in-python-is-a-bad-idea/

https://stackoverflow.com/questions/2386714/why-is-import-bad

https://medium.com/@s16h/importing-star-in-python-88fe9e8bd4d2

and people have written tools to replace them:

https://www.asmeurer.com/removestar/

Of course it is right and proper that people should be permitted to use wildcard imports. Consenting Adults applies.

But I am perplexed that people seem to be arguing that we can't add new names to modules because that would break code that does a wildcard import from that module. When did that become a thing?

I'm perplexed because, firstly, we have never guaranteed that modules won't add new names to their namespace. *Removing* names is a backwards- incompatible change. *Adding* names is not.

Python 3.9 added numerous new names to modules, including:

- ast.unparse - four new functions to the curses module - two new constants to fcntl - math.nextafter and .ulp

etc.

Secondly, in practice people do their wildcard imports at the start of the module, so they can make use of those names in their script or application:

from tkinter import * window = Tk()

If the module adds a new name that you aren't expecting and aren't using, it just sits there harmlessly in your application's namespace. It doesn't prevent you using that name for your own purposes, so it can't break your code unless you do the star import after other imports or definitions.

Sure, you can do that star import in the middle of your code. But consenting adults applies. If you do that, you're supposed to know what you are doing.

So we seem to be worrying about a non-problem here. Adding a new Infinity name to builtins, or some other module, won't break backwards compatibility.

But what will break backwards compatibility is either:

- making Infinity a keyword, like None;

- or changing the repr of math.inf to 'Infinity'.

[Stephen]

Also someone needs to explain how to avoid the debacle that was the the name collisions with True and False when the bool type was introduced.

What debacle are you referring to? Are you referring to the addition of the bools in the 2.2.1 bugfix release?

If so, we avoid that these days by just not adding new features to bugfix releases.

I don't know what name collisions you are referring to. In 2.2.1, new builtins bool (a function), True (the int 1) and False (the int 0) where added to allow people to backport code written for 2.3 which contained the proper bool type and special True/False singletons.

Adding these didn't cause name collisions. If your module already included globals

False = 0 True = not False

they would quitely and harmlessly shadow the builtins and all was well.

The whole transition was remarkable smooth:

- PEP 285 introduced a new builtin bool type, with two named singletons True and False;

https://www.python.org/dev/peps/pep-0285/

- a bool *function*, with two named values True=1 and False=0, were retroactively added to 2.2.1 (adding these to a bugfix release was an annoyance, but hardly a debacle);

- and the True and False names didn't become keywords until Python 3.

See here for more background on it:

https://python-history.blogspot.com/2013/11/story-of-none-true-false.html

https://python-history.blogspot.com/2013/11/the-history-of-bool-true-and-fal...

Steven D'Aprano writes:

Since when did `from foo import *` suddenly become a widely adopted coding practice?

Right here, a few lines later in your same post:

Secondly, in practice people do their wildcard imports at the start of the module, so they can make use of those names in their script or application[.]

Slow down, friend. You don't need to argue both sides of every issue.

On Fri, Sep 04, 2020 at 06:30:39PM -0400, Todd wrote:

It will break an ENORMOUS amount of code. Numpy has its own top-level "inf" variable. So all code that uses "from numpy import *" will break.

Yeah no.

py> import builtins py> builtins.inf = "Hello world!" py> inf 'Hello world!' py> from numpy import * py> inf inf

Making inf a keyword would certainly break code, but adding it to builtins would not.

By the way, the numpy inf is a float, so literally the same value and type as the proposed inf/Infinity builtin. The only way you could tell them apart is by identity tests.

It will break an ENORMOUS amount of code. Numpy has its own top-level "inf" variable. So all code that uses "from numpy import *" will break.

The fact that so many modules and packages must define an 'inf' is, to me, a signal that such a constant WOULD be useful. All of them (should) be referring to the same value, anyways, so why not make a global constant instead?

You can't argue that 'no one needs an infinity constant' and yet also giving evidence of code breakage of everyone having to define their own infinity constant. Surely you must see that these reasons are why I suggested the constant in the first place.

Now, obviously, numpy should probably define their own infinity just for completeness, because it is supposed to be a comprehensive package.

Perhaps the infinity constant should be a builtin which can be shadowed instead of a keyword (that way, no pre-existing code would break, except really weird code that only works if 'inf' is *not* defined).

---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

On Sat, Sep 5, 2020 at 1:00 PM Steven D'Aprano steve@pearwood.info wrote:

On Fri, Sep 04, 2020 at 06:30:39PM -0400, Todd wrote:

It will break an ENORMOUS amount of code. Numpy has its own top-level "inf" variable. So all code that uses "from numpy import *" will break.

Yeah no.

`py> import builtins py> builtins.inf = "Hello world!" py> inf 'Hello world!' py> from numpy import * py> inf inf`

Making inf a keyword would certainly break code, but adding it to builtins would not.

By the way, the numpy inf is a float, so literally the same value and type as the proposed inf/Infinity builtin. The only way you could tell them apart is by identity tests.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/73Z5N3... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 5, 2020 at 3:39 PM Cade Brown brown.cade@gmail.com wrote:

The fact that so many modules and packages must define an 'inf' is, to me, a signal that such a constant WOULD be useful. All of them (should) be referring to the same value, anyways, so why not make a global constant instead?

`pi` is a widely used constant that is defined in both numpy and math. `e` is a widely used constant that is defined in both numpy and math. Neither of them is included in builtins. What is different about `inf` or `Infinity`?

The only real goal I've seen is that you hope that `x == eval(repr(x))` for floating point numbers. But that is doomed to failure since it cannot work for NaN by its very definition. So with your change the situation would be: It doesn't work for floats in general, but it works for two additional floating point values that it didn't used to work for.... and even that only means that you don't want to type one import:

from math import inf inf == eval(repr(inf))

True

Lots of people have noted that being able to eval a repr is only a vague goal in Python, that works *often* at most.

---

Now if you want something genuinely useful, I wish we had an integer infinity. There are places where `float('inf')` just isn't suitable because of the wrong type.

Doing a grep of CPython source, it looks like `sys.maxsize` occurs 343 times, and in almost every one of them it is a stand-in for "infinity." I am certain there are other places where "a big number" is used because no integer infinity exists; sys.maxsize is only one spelling of that.

The general context where I'd want it is in code like this:

last = int.Infinity if not n:=smaller_last() else n good_stuff = all_stuff[first:last+1]

Or in a similar spirit, we might be looking for a bound, and run `bound = min(new_thing, bound)` in a loop. For that code, I need an initial value; albeit, in that case, float inf is probably fine. And if I'm writing code to count the number of books on my shelf, sys.maxsize is a perfectly good starting point as well. But int.Infinity expresses the actual intention more clearly.

You can absolutely represent pi or e with a constant (3.14159265358979....)

The same cannot be said for infinity, hence why it should be a constant rather than a function call to retrieve the value

On Sat, Sep 5, 2020, 4:08 PM David Mertz mertz@gnosis.cx wrote:

On Sat, Sep 5, 2020 at 3:39 PM Cade Brown brown.cade@gmail.com wrote:

The fact that so many modules and packages must define an 'inf' is, to me, a signal that such a constant WOULD be useful. All of them (should) be referring to the same value, anyways, so why not make a global constant instead?

`pi` is a widely used constant that is defined in both numpy and math. `e` is a widely used constant that is defined in both numpy and math. Neither of them is included in builtins. What is different about `inf` or `Infinity`?

The only real goal I've seen is that you hope that `x == eval(repr(x))` for floating point numbers. But that is doomed to failure since it cannot work for NaN by its very definition. So with your change the situation would be: It doesn't work for floats in general, but it works for two additional floating point values that it didn't used to work for.... and even that only means that you don't want to type one import:

from math import inf inf == eval(repr(inf))

True

Lots of people have noted that being able to eval a repr is only a vague goal in Python, that works *often* at most.

Now if you want something genuinely useful, I wish we had an integer infinity. There are places where `float('inf')` just isn't suitable because of the wrong type.

Doing a grep of CPython source, it looks like `sys.maxsize` occurs 343 times, and in almost every one of them it is a stand-in for "infinity." I am certain there are other places where "a big number" is used because no integer infinity exists; sys.maxsize is only one spelling of that.

The general context where I'd want it is in code like this:

last = int.Infinity if not n:=smaller_last() else n good_stuff = all_stuff[first:last+1]

Or in a similar spirit, we might be looking for a bound, and run `bound = min(new_thing, bound)` in a loop. For that code, I need an initial value; albeit, in that case, float inf is probably fine. And if I'm writing code to count the number of books on my shelf, sys.maxsize is a perfectly good starting point as well. But int.Infinity expresses the actual intention more clearly.

-- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.

About 20 people have pointed out that `inf` *IS* a constant. It's just in math rather then built-ins.

On Sat, Sep 5, 2020, 5:10 PM Cade Brown brown.cade@gmail.com wrote:

You can absolutely represent pi or e with a constant (3.14159265358979....)

The same cannot be said for infinity, hence why it should be a constant rather than a function call to retrieve the value

On Sat, Sep 5, 2020, 4:08 PM David Mertz mertz@gnosis.cx wrote:

On Sat, Sep 5, 2020 at 3:39 PM Cade Brown brown.cade@gmail.com wrote:

`pi` is a widely used constant that is defined in both numpy and math. `e` is a widely used constant that is defined in both numpy and math. Neither of them is included in builtins. What is different about `inf` or `Infinity`?

The only real goal I've seen is that you hope that `x == eval(repr(x))` for floating point numbers. But that is doomed to failure since it cannot work for NaN by its very definition. So with your change the situation would be: It doesn't work for floats in general, but it works for two additional floating point values that it didn't used to work for.... and even that only means that you don't want to type one import:

from math import inf inf == eval(repr(inf))

True

Lots of people have noted that being able to eval a repr is only a vague goal in Python, that works *often* at most.

Now if you want something genuinely useful, I wish we had an integer infinity. There are places where `float('inf')` just isn't suitable because of the wrong type.

Doing a grep of CPython source, it looks like `sys.maxsize` occurs 343 times, and in almost every one of them it is a stand-in for "infinity." I am certain there are other places where "a big number" is used because no integer infinity exists; sys.maxsize is only one spelling of that.

The general context where I'd want it is in code like this:

last = int.Infinity if not n:=smaller_last() else n good_stuff = all_stuff[first:last+1]

Or in a similar spirit, we might be looking for a bound, and run `bound = min(new_thing, bound)` in a loop. For that code, I need an initial value; albeit, in that case, float inf is probably fine. And if I'm writing code to count the number of books on my shelf, sys.maxsize is a perfectly good starting point as well. But int.Infinity expresses the actual intention more clearly.

-- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.

On 6/09/20 8:08 am, David Mertz wrote:

Still, the fact that it *almost* works for floats, except for certain specific values, is a bit annoying.

Maybe the solution is for the repr of a float to be float('inf') instead of just 'inf'.

That still wouldn't work with literal_eval, but I've realised that literal_eval only works on tuples, not lists, so it's of limited use anyway.

On 6/09/20 8:08 am, David Mertz wrote:

The only real goal I've seen is that you hope that `x == eval(repr(x))` for floating point numbers. But that is doomed to failure since it cannot work for NaN by its very definition.

I think that just means the definition needs a bit more finesse. It would be a reasonable goal for it to give back *some* NaN with the same flags and payload as the original.

On Sat, Sep 5, 2020 at 7:26 PM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 6/09/20 8:08 am, David Mertz wrote:

The only real goal I've seen is that you hope that `x == eval(repr(x))` for floating point numbers. But that is doomed to failure since it cannot work for NaN by its very definition.

I think that just means the definition needs a bit more finesse. It would be a reasonable goal for it to give back *some* NaN with the same flags and payload as the original.

Sure, but we have that already:

from math import inf, nan eval(repr([42, nan, inf]))

[42, nan, inf]

The only difference is the `math` namespace vs `builtins` namespace.

inf =3 eval(repr([1.0, 2.0, float('inf')]))

Obviously these are edge cases, and we could spent all day going over particular cases which the repr -> eval identity doesn't hold. However I still think that, as a principle, it's a solid one. I think changing the repr of 'inf' to 'float('inf')' is a decent solution (but keeping str conversion the same).

So, I guess in order to reduce backwards incompatibility, the repr could be modified to return a string which actually generates an infinite value

On Sat, Sep 5, 2020, 8:14 PM David Mertz mertz@gnosis.cx wrote:

On Sat, Sep 5, 2020 at 7:26 PM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 6/09/20 8:08 am, David Mertz wrote:

The only real goal I've seen is that you hope that `x == eval(repr(x))` for floating point numbers. But that is doomed to failure since it cannot work for NaN by its very definition.

I think that just means the definition needs a bit more finesse. It would be a reasonable goal for it to give back *some* NaN with the same flags and payload as the original.

Sure, but we have that already:

from math import inf, nan eval(repr([42, nan, inf]))

[42, nan, inf]

The only difference is the `math` namespace vs `builtins` namespace.

-- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/HP5R24... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 5, 2020 at 5:21 PM Cade Brown brown.cade@gmail.com wrote:

[...] we could spent all day going over particular cases which the repr -> eval identity doesn't hold. However I still think that, as a principle, it's a solid one. I think changing the repr of 'inf' to 'float('inf')' is a decent solution (but keeping str conversion the same).

So, I guess in order to reduce backwards incompatibility, the repr could be modified to return a string which actually generates an infinite value

I would assume that there's a lot of code, much of it not written in Python, that has been written to specifically look for this "inf" string. So I don't think we should change it. And making the repr() of floats different from their str() just in this one special case sounds like a bad idea too.

I don't think we could fix this one without making 'inf' a builtin constant, and I don't like that option at all. I also don't think this is quite as big a deal as it seems to have become in your head. So please put it to rest. There are many other worthy causes.

Fair enough, I guess people have managed without it and there are plenty of "good-enough" solutions for this that can be used in the place.

I can see it's probably not worth any code breakage for a more 'pure' design that ultimately is more of an aesthetic problem than one which is preventing real programs from being written

On Sat, Sep 5, 2020, 11:02 PM Guido van Rossum guido@python.org wrote:

On Sat, Sep 5, 2020 at 5:21 PM Cade Brown brown.cade@gmail.com wrote:

[...] we could spent all day going over particular cases which the repr -> eval identity doesn't hold. However I still think that, as a principle, it's a solid one. I think changing the repr of 'inf' to 'float('inf')' is a decent solution (but keeping str conversion the same).

So, I guess in order to reduce backwards incompatibility, the repr could be modified to return a string which actually generates an infinite value

I would assume that there's a lot of code, much of it not written in Python, that has been written to specifically look for this "inf" string. So I don't think we should change it. And making the repr() of floats different from their str() just in this one special case sounds like a bad idea too.

I don't think we could fix this one without making 'inf' a builtin constant, and I don't like that option at all. I also don't think this is quite as big a deal as it seems to have become in your head. So please put it to rest. There are many other worthy causes.

-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/

You might be interested in https://pypi.org/project/extended-int/

On Sunday, September 6, 2020 at 12:41:04 AM UTC-4 Cade Brown wrote:

Fair enough, I guess people have managed without it and there are plenty of "good-enough" solutions for this that can be used in the place.

I can see it's probably not worth any code breakage for a more 'pure' design that ultimately is more of an aesthetic problem than one which is preventing real programs from being written

On Sat, Sep 5, 2020, 11:02 PM Guido van Rossum gu...@python.org wrote:

On Sat, Sep 5, 2020 at 5:21 PM Cade Brown brown...@gmail.com wrote:

[...] we could spent all day going over particular cases which the repr -> eval identity doesn't hold. However I still think that, as a principle, it's a solid one. I think changing the repr of 'inf' to 'float('inf')' is a decent solution (but keeping str conversion the same).

I would assume that there's a lot of code, much of it not written in Python, that has been written to specifically look for this "inf" string. So I don't think we should change it. And making the repr() of floats different from their str() just in this one special case sounds like a bad idea too.

I don't think we could fix this one without making 'inf' a builtin constant, and I don't like that option at all. I also don't think this is quite as big a deal as it seems to have become in your head. So please put it to rest. There are many other worthy causes.

-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/

On Sat, Sep 5, 2020 at 10:00 AM Steven D'Aprano steve@pearwood.info wrote:

By the way, the numpy inf is a float, so literally the same value and type as the proposed inf/Infinity builtin. The only way you could tell them apart is by identity tests.

which is the case for any other float -- or, indeed any other two instances of a type that have the same value.

It seems this idea has gotten a bit sidetracked by, shall we say, a lack of precision in the conversation. So a few points:

math.inf or numpy,inf or, indeed float('inf") are not a special type or special object or anything else. each of these produces exactly the same thing -- a float with a particular value.

I noted a comment here about how odd it was to constructing a float with a function call and a string: float('inf') , but that is no different than any other use of the float type object with a string: float('0.1') works just fine -- and has been pointed out, that's how you create Decimals and many other types as well.

So what IS special here? What's special is that we have a literal syntax for only a few special fundamental types: floats, ints, strings. (I htin that's it, yes?), as well as "display" versions of a few core container types: list, dict, etc.

So the limitation here is that floats have a literal, and can have a huge number of values, all of which can be created by a literal, except inf, -in, and NaN (and the special versions of NaN ...).

Is this a limitation? sure it is. Is it critically important? obviously not, people have been productive with Python for decades. Would it be nice and at least sometimes useful to be able to have a literal for inf and NaN? yes.

It's also the case that Python used to have even worse support for the float special values, there was PEP 754, which was rejected (notably due to lack of activity, not an all out rejection), but "Several ideas of this PEP were implemented for Python 2.6. float('inf') and repr(float('inf')) are now guaranteed to work on every supported platform with IEEE 754 semantics" -- which got us far enough.

So this is not the same as None, or adding True and False

So, I *think* what we are talking about here is not a "new" value or a new keyword, but rather an extension to what is considered a valid "literal". There may be technical limitations that I don't understand, but the proposal would be that the text ``inf`` and ``nan`` would be valid everywhere a float literal was valid, i.e.:

ast.literal_eval("inf") would produce a float with the IEEE inf value (similar for ``nan``) rather than being an error where it is now.

Would that require that it be a keyword? I don't think so, couldn't it be "just a name" in most contexts, like "True" was in py2, which did work in ast.literal_eval()? But if the only way to get them to be evaluated as literals would be to make them keywords, then this idea is dead in the water.

-CHB

On 7/09/20 6:03 am, Christopher Barker wrote:

Would that require that it be a keyword? I don't think so, couldn't it be "just a name" in most contexts, like "True" was in py2, which did work in ast.literal_eval()?

There could be a special bytecode that looks it up as a name, and if that doesn't work, returns float('inf'). But then you might as well make it a built-in name, which would behave almost exactly the same way, and Guido doesn't want to do that.

On Mon, Sep 7, 2020 at 9:47 AM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 7/09/20 6:03 am, Christopher Barker wrote:

Would that require that it be a keyword? I don't think so, couldn't it be "just a name" in most contexts, like "True" was in py2, which did work in ast.literal_eval()?

There could be a special bytecode that looks it up as a name, and if that doesn't work, returns float('inf'). But then you might as well make it a built-in name, which would behave almost exactly the same way, and Guido doesn't want to do that.

For it to work in ast.literal_eval, it has to have a special form in the Abstract Syntax Tree. Play around with it using something like this:

ast.dump(ast.parse(some_code, mode='eval').body)

and you'll see that the magic constants (eg True) have an AST node of type "Constant", as do literals that represent constants. (Note that by the time you get there, the textual representation is gone. You can't distinguish octal or hex constants once they just become integers.) Name lookups, on the other hand, are quite different. If "inf" were to do a name lookup with a fallback, it'd be much more similar to name lookups than to constants, and it'd definitely need special handling inside literal_eval.

And if it's going to get special handling, it'd be way WAY cleaner to just build a function similar to literal_eval that permits exactly the operations you're okay with. For instance, Name lookups (in a Load context) that can be satisfied from a specific dictionary; or all Name lookups but no Attribute referencing; or allow basic arithmetic operations (+-*/) but disallow function calls; or whatever you like. Check out the source code for literal_eval and you'll see that it's fairly simple: it does an AST parse on the text string, then recursively walks the syntax tree using its own evaluator, raising an exception if it finds something it doesn't want to work with.

ChrisA

But then you might as

well make it a built-in name, which would behave almost exactly

the same way, and Guido doesn't want to do that.

Do you have a reference for that preference? And Guido is no longer the

BDFL, though of course, very well respected opinion.

and you'll see that the magic constants (eg True) have an AST node of

type "Constant", as do literals that represent constants.

That sounds like the “right” thing to do with this, if anything.

similar to name lookups than to constants, and it'd definitely need

special handling inside literal_eval.

Which is why just adding these to the builtin names doesn’t quite do it.

it'd be way WAY cleaner to

just build a function similar to literal_eval that permits exactly the

operations you're okay with.

Sure, that would be the way to make a “PYSON” reader like I would like, but that’s not really the goal of this proposal, such as it is — making “inf” work with literal_eval is not so much the goal, as a shorthand for what I guess is:

Make “inf” and “nan” Constants.

The idea is that, if the names have not been defined in that scope, they would behave like any other literal everywhere in Python.

I’m actually liking this more as I think about it. And it seems it wouldn’t actually break any code that currently defines those names. And in many cases, it would do the same thing as those names currently do, if a bit differently.

That is, if you removed:

from math import inf

From your code, nothing would break.

I honestly don’t think I want this enough to try to push it through, but it’s a

+1

From me, for what that’s worth (two cents, maybe? )

-CHB

--

Christopher Barker, PhD

Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Tue, Sep 8, 2020 at 9:21 AM Christopher Barker pythonchb@gmail.com wrote:

I’m actually liking this more as I think about it. And it seems it wouldn’t actually break any code that currently defines those names. And in many cases, it would do the same thing as those names currently do, if a bit differently.

That is, if you removed:

from math import inf

From your code, nothing would break.

Everything would break. On versions prior to the one that introduced the new literal form, you MUST have that line, or your code won't work. On versions starting with that one, you MUST NOT have that line, as it would be a SyntaxError. That's an awful lot of breakage for such a tiny benefit.

ChrisA

That is, if you removed:

from math import inf

From your code, nothing would break.

Everything would break. On versions prior to the one that introduced the new literal form, you MUST have that line, or your code won't work.

But it’s already there.

On versions starting with that one, you MUST NOT have that line,

as it would be a SyntaxError.

Huh? I was proposing doing it like was done for True and False in Python 2:

(python 2.7)

In [1]: from bools import True, False

In [7]: print True, False 1 0

but True and False are still "special" at least with ast.literal_eval:

In [8]: ast.literal_eval("[True, False]") Out[8]: [True, False]

I fully agree that this "tiny benefit" is not worth breaking a lot (or hardly any) code. But it seems it can be done with very little breakage.

In fact, this is even less likely to break code than the introduction of True and False were, 'cause math,inf and numpy,inf actually do return a float with the value of inf - the very same type and value that this would produce. And frankly, it would get used a LOT less than True and False are as well.

-CHB

On Tue, Sep 8, 2020 at 3:42 PM Christopher Barker pythonchb@gmail.com wrote:

On versions starting with that one, you MUST NOT have that line, as it would be a SyntaxError.

Huh? I was proposing doing it like was done for True and False in Python 2:

They were just builtins, not keywords at all.

but True and False are still "special" at least with ast.literal_eval:

In [8]: ast.literal_eval("[True, False]") Out[8]: [True, False]

I fully agree that this "tiny benefit" is not worth breaking a lot (or hardly any) code. But it seems it can be done with very little breakage.

Yes - literal_eval in Python 2.7 had a whitelist of valid names. Exactly like I'd been suggesting earlier. :) If you want "inf" to be special, write your own literal_eval that treats it as special. It's really not hard. CPython is open source, and the ast module is written in Python, so you can just go look at how it works :)

ChrisA

Given that this is unlikely to see any change in core Python, perhaps you can get a decent solution with a third party library? If your main issue is that repr doesn't provide an "eval-able" string, then may I suggest using the "most-used" function in the ubelt utility library: ubelt.repr2

Two main goals of repr2 are to provide nice string representations of nested data structures and make those "eval-able" whenever possible. As an example take the value `float('inf')`, which normaly has a non-evalable repr of `inf`:

!pip install ubelt import ubelt as ub ub.repr2(float('inf'))

"float('inf')"

The `newline` (or `nl`) keyword argument can control how deep in the nesting newlines are allowed.

print(ub.repr2({1: float('nan'), 2: float('inf'), 3: 3.0}))

{ 1: float('nan'), 2: float('inf'), 3: 3.0, }

print(ub.repr2({1: float('nan'), 2: float('inf'), 3: 3.0}, nl=0))

{1: float('nan'), 2: float('inf'), 3: 3.0}

You can also define or overwrite how representations for different types are created. You can either create your own extension object, or you can monkey-patch `ub.util_format._FORMATTER_EXTENSIONS` without specifying the extensions keyword argument (although this will be a global change).

extensions = ub.FormatterExtensions() @extensions.register(float) def my_float_formater(data, **kw): return "monkey({})".format(data) print(ub.repr2({1: float('nan'), 2: float('inf'), 3: 3.0}, nl=0,

extensions=extensions)) {1: monkey(nan), 2: monkey(inf), 3: monkey(3.0)}

On Fri, Sep 4, 2020 at 12:49 PM Cade Brown brown.cade@gmail.com wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

I think there are a number of good reasons for this constant. For example:

- It is also a fundamental constant (similar to True, False, and None),
and should be representable as such in the language

- Requiring a cast from float to string is messy, and also obviously

- It would make the useful property that `eval(repr(x)) == x` for
floating point numbers (currently, `NameError: name 'inf' is not defined`)

This makes it difficult to, for example, naively serialize a list of floats. For example:

A few rebuttals/claims against:

- Creating a new constant (Infinity) which is unassignable may break
existing code

- Converting a float to string is not the same as it is in C. Whil
## Thanks,

Thanks Jon and Chris. But I'm not looking to make a literal_eval or custom reprs that support inf and nan -- I may need that some day, so thanks for the tips, but the idea here is to do that little bit more to make Python better support the float special values out of the box.

It seems that moving math,inf and math.nan to __builtins__, and adding them to a "whitelist" in literal_eval (and maybe another place or two?) would accomplish this. Small benefit, yes, but I have yet to hear anyone present a downside (other than the usual it's work that someone has to do).

I took another look at PEP 754 (which was rejected due to disinterest, not because it was determined to be a bad idea), and note that the only part that wasn't implemented was the creation of "constants" in __builtins__ (and, indeed, the PEP is not clear on whether it was suggesting that they be in __builtins__ at all). The PEP also called for different names, and a constant for negative Infinity, which doesn't seem very useful when you can just use a negative sign.

Anyway, I'm done now -- there hasn't been any interest from core devs, and I don't care enough to push this, but it would be nice.

-CHB

If you and Cade want to co-author a PEP that adds `inf` and `nan` to the builtins, I'll sponsor it, so you can have a fair hearing from the SC. I won't argue in favor, but not against either.)

On Tue, Sep 8, 2020 at 6:26 PM Christopher Barker pythonchb@gmail.com wrote:

Thanks Jon and Chris. But I'm not looking to make a literal_eval or custom reprs that support inf and nan -- I may need that some day, so thanks for the tips, but the idea here is to do that little bit more to make Python better support the float special values out of the box.

It seems that moving math,inf and math.nan to __builtins__, and adding them to a "whitelist" in literal_eval (and maybe another place or two?) would accomplish this. Small benefit, yes, but I have yet to hear anyone present a downside (other than the usual it's work that someone has to do).

I took another look at PEP 754 (which was rejected due to disinterest, not because it was determined to be a bad idea), and note that the only part that wasn't implemented was the creation of "constants" in __builtins__ (and, indeed, the PEP is not clear on whether it was suggesting that they be in __builtins__ at all). The PEP also called for different names, and a constant for negative Infinity, which doesn't seem very useful when you can just use a negative sign.

Anyway, I'm done now -- there hasn't been any interest from core devs, and I don't care enough to push this, but it would be nice.

-CHB

-- Christopher Barker, PhD

Python Language Consulting

- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4VK6ND... Code of Conduct: http://python.org/psf/codeofconduct/

All,

For reference, my PEP repo: https://github.com/CadeBrown/peps

Guido,

Thanks for helping out. And yes I'd be interested in writing a PEP. I'm forking the repository (as mentioned above in my message). Where should discussion specific to the PEP take place? Should we move to 1-on-1 email conversations, or should it be kept in the public mailing list?

Thanks, ---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

On Tue, Sep 8, 2020 at 11:48 PM Guido van Rossum guido@python.org wrote:

If you and Cade want to co-author a PEP that adds `inf` and `nan` to the builtins, I'll sponsor it, so you can have a fair hearing from the SC. I won't argue in favor, but not against either.)

On Tue, Sep 8, 2020 at 6:26 PM Christopher Barker pythonchb@gmail.com wrote:

Thanks Jon and Chris. But I'm not looking to make a literal_eval or custom reprs that support inf and nan -- I may need that some day, so thanks for the tips, but the idea here is to do that little bit more to make Python better support the float special values out of the box.

It seems that moving math,inf and math.nan to __builtins__, and adding them to a "whitelist" in literal_eval (and maybe another place or two?) would accomplish this. Small benefit, yes, but I have yet to hear anyone present a downside (other than the usual it's work that someone has to do).

I took another look at PEP 754 (which was rejected due to disinterest, not because it was determined to be a bad idea), and note that the only part that wasn't implemented was the creation of "constants" in __builtins__ (and, indeed, the PEP is not clear on whether it was suggesting that they be in __builtins__ at all). The PEP also called for different names, and a constant for negative Infinity, which doesn't seem very useful when you can just use a negative sign.

Anyway, I'm done now -- there hasn't been any interest from core devs, and I don't care enough to push this, but it would be nice.

-CHB

-- Christopher Barker, PhD

Python Language Consulting

- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4VK6ND... Code of Conduct: http://python.org/psf/codeofconduct/

-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/

The discussion on this list is plenty. Just write the PEP!

On Wed, Sep 9, 2020 at 12:07 PM Cade Brown brown.cade@gmail.com wrote:

All,

For reference, my PEP repo: https://github.com/CadeBrown/peps

Guido,

Thanks for helping out. And yes I'd be interested in writing a PEP. I'm forking the repository (as mentioned above in my message). Where should discussion specific to the PEP take place? Should we move to 1-on-1 email conversations, or should it be kept in the public mailing list?

## Thanks,

On Tue, Sep 8, 2020 at 11:48 PM Guido van Rossum guido@python.org wrote:

If you and Cade want to co-author a PEP that adds `inf` and `nan` to the builtins, I'll sponsor it, so you can have a fair hearing from the SC. I won't argue in favor, but not against either.)

On Tue, Sep 8, 2020 at 6:26 PM Christopher Barker pythonchb@gmail.com wrote:

-CHB

-- Christopher Barker, PhD

Python Language Consulting

- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4VK6ND... Code of Conduct: http://python.org/psf/codeofconduct/

On Wed, Sep 9, 2020 at 12:36 PM Guido van Rossum guido@python.org wrote:

The discussion on this list is plenty. Just write the PEP!

Indeed. I'm happy to help with the writing, and if anyone else watching this thread would like to help out, let us know.

Otherwise, the next step is a draft PEP.

Cade, I'm happy to work in your fork if you like. Let's coordinate offline.

-CHB

On Wed, Sep 9, 2020 at 12:07 PM Cade Brown brown.cade@gmail.com wrote:

All,

For reference, my PEP repo: https://github.com/CadeBrown/peps

Guido,

Thanks for helping out. And yes I'd be interested in writing a PEP. I'm forking the repository (as mentioned above in my message). Where should discussion specific to the PEP take place? Should we move to 1-on-1 email conversations, or should it be kept in the public mailing list?

## Thanks,

On Tue, Sep 8, 2020 at 11:48 PM Guido van Rossum guido@python.org wrote:

On Tue, Sep 8, 2020 at 6:26 PM Christopher Barker pythonchb@gmail.com wrote:

-CHB

-- Christopher Barker, PhD

Python Language Consulting

- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

On Fri, Sep 4, 2020, at 12:45, Cade Brown wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

What if we created a new syntax [and used it for the repr] that is not currently a valid identifier?

something like "1.INF"

On Fri, Sep 11, 2020 at 3:09 AM Random832 random832@fastmail.com wrote:

On Fri, Sep 4, 2020, at 12:45, Cade Brown wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

What if we created a new syntax [and used it for the repr] that is not currently a valid identifier?

something like "1.INF"

This is out of the box and might be considered insane, but what about:

INF#

INF#

INF # this is a comment as usual

NameError: INF

But I suppose this would be considered a breaking change, since the text "INF#" probably exists in code somewhere.

--- Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

This syntax seems ugly to me, clunky, and as you said probably breaks existing code

This, to me, is less clear than current methods of generating an 'inf' which is the whole reason I proposed it

On Fri, Sep 11, 2020 at 9:38 AM Ricky Teachey ricky@teachey.org wrote:

On Fri, Sep 11, 2020 at 3:09 AM Random832 random832@fastmail.com wrote:

On Fri, Sep 4, 2020, at 12:45, Cade Brown wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

What if we created a new syntax [and used it for the repr] that is not currently a valid identifier?

something like "1.INF"

This is out of the box and might be considered insane, but what about:

INF#

INF#

INF # this is a comment as usual

NameError: INF

But I suppose this would be considered a breaking change, since the text "INF#" probably exists in code somewhere.

Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/VAJC2I... Code of Conduct: http://python.org/psf/codeofconduct/

On Fri, Sep 11, 2020 at 12:09 AM Random832 random832@fastmail.com wrote:

On Fri, Sep 4, 2020, at 12:45, Cade Brown wrote:

I am positing that Python should contain a constant (similar to True, False, None), called Infinity.

What if we created a new syntax [and used it for the repr] that is not currently a valid identifier?

something like "1.INF"

if we were starting from scratch, that would be a good idea, but as the repr has been consistent for quite some timem I dont think we want to change it. And we do want teh names to match the repr

And I'd maybe go with .INF. :-)

Another point is that these are not going to be singletons, like True, False and None -- they are just floats that happen to have particular values.

-CHB

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/BN5ZRN... Code of Conduct: http://python.org/psf/codeofconduct/

Christopher Barker writes:

On Fri, Sep 11, 2020 at 12:09 AM Random832 random832@fastmail.com wrote:

What if we created a new syntax [and used it for the repr] that is not currently a valid identifier?

something like "1.INF"

Not for this please; save it for a case where we need it. I'm against any change by TOOWTDI and because inf and nan only exist in Python the language (including builtins) via casting strings to floats (there are no arithmetic operations that produce them). It seems right and proper to me that you import these from math (amusingly, math by itself doesn't seem to be enough to produce inf: the closest I've found is math.tan(math.pi/2.0) = 1.633123935319537e+16, and of course math.cot doesn't exist, while math.cos(0.0)/math.sin(0.0) just gives a ZeroDivisionError).

But if there is going to be a change, just import inf and nan into the builtin namespace as identifiers. Steven d'Aprano made a pretty convincing case that you have to do something pretty perverse for this to cause trouble.

Christopher Barker writes:

And I'd maybe go with .INF. :-)

Syntax using a leading dot has been proposed multiple times, most recently in the pattern matching thread (PEP 622 I think?). In the past it has been proposed as an abbreviation for the self.x = x pattern in __init__, and also in a Pascal-like with statement. I don't think we want to use it for something as small as fixing up one repr.

Another point is that these are not going to be singletons, like True, False and None

Singleton isn't the problem here. inf = None causes no problems if that's what you want to do. It's that those three names are keywords, and can't be used as identifiers. True and False caused problems because by introducing them the common idiom "False, True = 0, 1" became a syntax error.

-- they are just floats that happen to have particular values.

s/floats/identifiers/

The values are floats, but inf and nan are syntactically identifiers, not floats.

On Fri, Sep 11, 2020 at 6:48 AM Stephen J. Turnbull

inf and nan only exist in Python the

language (including builtins) via casting strings to floats (there are

no arithmetic operations that produce them).

import sys; sys.version

'3.8.3 (default, May 19 2020, 18:47:26) \n[GCC 7.3.0]'

from math import pi as π exp = 2**9 a = (22/7) ** exp1 b = π ** exp1 a

4.2679182652117097e+254

a * a

inf

(a*a)/(b*b)

nan

--- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.

What's wrong with 1e1000?

On Fri, Sep 11, 2020 at 11:51 AM David Mertz mertz@gnosis.cx wrote:

On Fri, Sep 11, 2020 at 6:48 AM Stephen J. Turnbull

inf and nan only exist in Python the

language (including builtins) via casting strings to floats (there are

no arithmetic operations that produce them).

import sys; sys.version

'3.8.3 (default, May 19 2020, 18:47:26) \n[GCC 7.3.0]'

from math import pi as π exp = 2**9 a = (22/7) ** exp1 b = π ** exp1 a

4.2679182652117097e+254

a * a

inf

(a*a)/(b*b)

nan

The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SI55GC... Code of Conduct: http://python.org/psf/codeofconduct/

On Fri, Sep 11, 2020 at 8:58 AM Guido van Rossum guido@python.org wrote:

What's wrong with 1e1000?

As a spelling of "infinity" generically, or just as an example of an "arithmetic operation"?

On the latter, I didn't use that just because it feels sort of like a "cheat" rather than an "operation." I.e. my longer example started out with some "reasonable" numbers, but wound up tripping into inf and nan.

On Fri, Sep 11, 2020 at 1:10 PM David Mertz mertz@gnosis.cx wrote:

On Fri, Sep 11, 2020 at 8:58 AM Guido van Rossum guido@python.org wrote:

What's wrong with 1e1000?

As a spelling of "infinity" generically, or just as an example of an "arithmetic operation"?

On the latter, I didn't use that just because it feels sort of like a "cheat" rather than an "operation." I.e. my longer example started out with some "reasonable" numbers, but wound up tripping into inf and nan.

Presumably this is all meant to counter Stephen Turnbull's claim:

inf and nan only exist in Python the

language (including builtins) via casting strings to floats (there are

no arithmetic operations that produce them).

While one may argue that writing `1e1000` is not an "arithmetic operation", certainly it's certainly not "casting strings to floats", and it's the simeplest way of producing `inf` in a pinch (in theory it's not portable, but I think "in a pinch" means you don't care about that).

I don't actually understand why Stephen made this claim about arithmetic operations, since inf and nan exist *exactly* because arithmetic operations may produce them. And you don't need to involve pi either, just `1e300 * 1e300` does it.

On Fri, Sep 11, 2020 at 10:19 AM Guido van Rossum guido@python.org wrote:

While one may argue that writing `1e1000` is not an "arithmetic operation", certainly it's certainly not "casting strings to floats", and it's the simeplest way of producing `inf` in a pinch (in theory it's not portable, but I think "in a pinch" means you don't care about that).

For 128-bit versions of Python you'd need 1e4933. For 256-bit, 1e78914. But those work fine on 32-bit or 64-bit also.

I don't actually understand why Stephen made this claim about arithmetic

operations, since inf and nan exist *exactly* because arithmetic operations may produce them. And you don't need to involve pi either, just `1e300 * 1e300` does it.

Yeah, pi was irrelevant in my example. It's just something from my writing for hypothetical code that does stuff with 22/7 vs. with pi to see how different they are.

On Fri, Sep 11, 2020 at 11:19:05AM -1000, David Mertz wrote:

On Fri, Sep 11, 2020 at 10:19 AM Guido van Rossum guido@python.org wrote:

While one may argue that writing `1e1000` is not an "arithmetic operation", certainly it's certainly not "casting strings to floats", and it's the simeplest way of producing `inf` in a pinch (in theory it's not portable, but I think "in a pinch" means you don't care about that).

I think that the only reason that could fail to produce inf is if your C doubles aren't IEEE-754 binary64.

Are there any such platforms that are capable of building CPython but don't support IEEE-754? Or has anyone tried building CPython using, for example, posits instead?

For 128-bit versions of Python you'd need 1e4933. For 256-bit, 1e78914. But those work fine on 32-bit or 64-bit also.

Are there any Pythons with 128-bit or 256-bit floats?

I've just tried Jython and IronPython, and got:

>>> sys.float_info.max_10_exp 308L

for both of them, which matches CPython.

Micropython doesn't seem to support sys.float_info, but testing suggests that the floats are 64 bit too:

# Micropython 1.9, Python version 3.4 >>> 1e309 inf

If anyone is seriously worried about their Python supporting more than 64 bit floats, you can use 1e80000 which should give inf on any system supporting IEEE-754 no matter what size floats you have. What it will do on a posit or other non-IEEE-754 machine, I have no idea :-)

Guido van Rossum writes:

I don't actually understand why Stephen made this claim about arithmetic operations,

Stephen is often mistaken about computers (among many topics). That's why he mostly posts on -ideas, and mostly throws drafts away rather than post them. :-)

I would not claim that evaluating a literal such as 1e1000 is not an arithmetic operation, I just "forgot" that these examples exist (mostly in a context of trying to get NaN with math.asin(2) and got ValueError instead ;-/ ).

I still stand by the argument that since some common ways of producing true infinities (rather than overflows) and NaNs such as 1.0/0.0 and 0.0/0.0 end up as Exceptions rather than float values, inf and nan have rather small usefulness in Python with only builtins, especially nan. "from math import inf" has to be the least annoying thing about working with infinities and overflows in Python (which, to be fair, is quite annoying in any context, on computers or on paper).

If, in the future, Python used a library such as MPFR and made all floats a given precision (say, by giving a flag to the interpreter "python -prec2048"), it would never be enough to make infinity because it only has the limitation of a 64 bit exponent.

This is just an example of course, probably won't happen, but when I read "1e1000" or such a number it doesn't strike me as infinite (although a particular version of IEEE floating point may consider it that), it strikes me as a lazy programmer who thinks it's bigger than any other number he's processing. I've added this case to my PEP .rst file and why it's not a good solution

Thanks, Cade

On Sat, Sep 12, 2020, 8:25 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Guido van Rossum writes:

I don't actually understand why Stephen made this claim about arithmetic operations,

Stephen is often mistaken about computers (among many topics). That's why he mostly posts on -ideas, and mostly throws drafts away rather than post them. :-)

I would not claim that evaluating a literal such as 1e1000 is not an arithmetic operation, I just "forgot" that these examples exist (mostly in a context of trying to get NaN with math.asin(2) and got ValueError instead ;-/ ).

I still stand by the argument that since some common ways of producing true infinities (rather than overflows) and NaNs such as 1.0/0.0 and 0.0/0.0 end up as Exceptions rather than float values, inf and nan have rather small usefulness in Python with only builtins, especially nan. "from math import inf" has to be the least annoying thing about working with infinities and overflows in Python (which, to be fair, is quite annoying in any context, on computers or on paper). _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/22TKQD... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 12, 2020 at 11:06:35AM -0400, Cade Brown wrote:

If, in the future, Python used a library such as MPFR and made all floats a given precision (say, by giving a flag to the interpreter "python -prec2048"), it would never be enough to make infinity because it only has the limitation of a 64 bit exponent.

Nobody is recommending that the best way to create an infinity is by writing 1e1000 or whatever other out of range number you choose. We're not using Python 2.4 anymore, and the correct ways to create an infiniy float is one of:

float('inf') from math import inf

(Or rather, most of us aren't using Python 2.4 anymore. For my sins, I am still maintaining code that is expected to run back to 2.4. Yay.)

Using something like 1e1000 (or choose a larger exponent) is a fall back for when nothing else works, and if that trick doesn't work either, then you have no hope for it, you are running on some weird machine without IEEE-754 semantics and there probably isn't an infinity at all.

In my own code I have something like this:

try: from math import inf except ImportError: try: inf = float('inf') except ValueError: # Could be Windows in 2.4 or 2.5? try: inf = float('1.#INF') except ValueError: # Desperate times require desperate measures. try: inf = 1e1000 assert inf > 0 and inf == 2*inf except (OverflowError, AssertionError): # Just give up, there is no infinity available. pass

Fortunately, I don't have to support some hypothetical future Python with 2048 bit non-IEEE-754 floats, but if I did, I'm sure that the import from math would work and the rest of the nested blocks would never be called.

This is just an example of course, probably won't happen, but when I read "1e1000" or such a number it doesn't strike me as infinite (although a particular version of IEEE floating point may consider it that), it strikes me as a lazy programmer who thinks it's bigger than any other number he's processing.

Well, I guess the code above makes me a lazy programmer.

not really relevant anyway, but the issue with using a really large literal to get Infinity is not that some possible future system could hold really huge numbers, but whether a too-large-for-the-implimentation literal get evaluated as Inf at all.

Is there any guarantee in Python or the C spec, or the IEEE spec that, e.g.:

1e10000

would create an Inf value, rather than an error of some sort?

It apparently works in all cases anyone in this thread has tried (and me too), but is it guaranteed anywhere?

And there's still NaN -- any way to get that with a literal?

-CHB

On Sat, Sep 12, 2020 at 10:34 AM Steven D'Aprano steve@pearwood.info wrote:

On Sat, Sep 12, 2020 at 11:06:35AM -0400, Cade Brown wrote:

If, in the future, Python used a library such as MPFR and made all

floats a

given precision (say, by giving a flag to the interpreter "python -prec2048"), it would never be enough to make infinity because it only

has

the limitation of a 64 bit exponent.

Nobody is recommending that the best way to create an infinity is by writing 1e1000 or whatever other out of range number you choose. We're not using Python 2.4 anymore, and the correct ways to create an infiniy float is one of:

`float('inf') from math import inf`

(Or rather, most of us aren't using Python 2.4 anymore. For my sins, I am still maintaining code that is expected to run back to 2.4. Yay.)

Using something like 1e1000 (or choose a larger exponent) is a fall back for when nothing else works, and if that trick doesn't work either, then you have no hope for it, you are running on some weird machine without IEEE-754 semantics and there probably isn't an infinity at all.

In my own code I have something like this:

`try: from math import inf except ImportError: try: inf = float('inf') except ValueError: # Could be Windows in 2.4 or 2.5? try: inf = float('1.#INF') except ValueError: # Desperate times require desperate measures. try: inf = 1e1000 assert inf > 0 and inf == 2*inf except (OverflowError, AssertionError): # Just give up, there is no infinity available. pass`

Fortunately, I don't have to support some hypothetical future Python with 2048 bit non-IEEE-754 floats, but if I did, I'm sure that the import from math would work and the rest of the nested blocks would never be called.

This is just an example of course, probably won't happen, but when I read "1e1000" or such a number it doesn't strike me as infinite (although a particular version of IEEE floating point may consider it that), it

strikes

me as a lazy programmer who thinks it's bigger than any other number he's processing.

Well, I guess the code above makes me a lazy programmer.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NH7O6A... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 12, 2020 at 12:56:25PM -0700, Christopher Barker wrote:

Is there any guarantee in Python or the C spec, or the IEEE spec that, e.g.:

1e10000

would create an Inf value, rather than an error of some sort?

IEEE-754 requires that float literals overflow to infinity.

I don't have a source for this (I cannot find a copy of the IEEE-754 standard except behind paywalls) but I have a very strong memory of either Tim Peters and Mark Dickinson stating this, and I believe them. (If either of them are reading this, please confirm or deny.)

And there's still NaN -- any way to get that with a literal?

If you have an INF, then you can generate a NAN with `INF - INF`.

In general though, Python doesn't support generating the full range of NANs with payloads directly.

On Sat, Sep 12, 2020, 2:02 PM Steven D'Aprano steve@pearwood.info wrote:

In general though, Python doesn't support generating the full range of NANs with payloads directly.

I've researched this a little bit for discussion in a book I'm writing, and I have not been able to identify ANY widely used programming language or tool that does anything meaningful with the NaN payloads.

It's possible I've missed something, but certainly not the top 20 languages are libraries that might come to mind.

As per tagged nans, check for JavaScript tagged NaN optimization. Essentially, the tag of the NaN (i.e. the mantissa) is interpreted as a pointer. Obviously, this is a very advanced use case, probably not worth Python guaranteeing such behavior. Here is one article: https://brionv.com/log/2018/05/17/javascript-engine-internals-nan-boxing/

On Sat, Sep 12, 2020, 8:10 PM David Mertz mertz@gnosis.cx wrote:

On Sat, Sep 12, 2020, 2:02 PM Steven D'Aprano steve@pearwood.info wrote:

In general though, Python doesn't support generating the full range of NANs with payloads directly.

I've researched this a little bit for discussion in a book I'm writing, and I have not been able to identify ANY widely used programming language or tool that does anything meaningful with the NaN payloads.

It's possible I've missed something, but certainly not the top 20 languages are libraries that might come to mind. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/FZ7QGR... Code of Conduct: http://python.org/psf/codeofconduct/

I probably should have added "user exposed" or something to my comment. Those extra bits certainly seem to offer compiler optimization possibilities, as apparently SpiderMonkey does with WASM.

I can easily *imagine* a library like NumPy or PyTorch deciding to expose something useful with those 52 unused mantissa bits. But that's some future version, if ever.

On Sat, Sep 12, 2020, 2:16 PM Cade Brown brown.cade@gmail.com wrote:

As per tagged nans, check for JavaScript tagged NaN optimization. Essentially, the tag of the NaN (i.e. the mantissa) is interpreted as a pointer. Obviously, this is a very advanced use case, probably not worth Python guaranteeing such behavior. Here is one article: https://brionv.com/log/2018/05/17/javascript-engine-internals-nan-boxing/

On Sat, Sep 12, 2020, 8:10 PM David Mertz mertz@gnosis.cx wrote:

On Sat, Sep 12, 2020, 2:02 PM Steven D'Aprano steve@pearwood.info wrote:

In general though, Python doesn't support generating the full range of NANs with payloads directly.

I've researched this a little bit for discussion in a book I'm writing, and I have not been able to identify ANY widely used programming language or tool that does anything meaningful with the NaN payloads.

It's possible I've missed something, but certainly not the top 20 languages are libraries that might come to mind. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/FZ7QGR... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 12, 2020 at 08:16:36PM -0400, Cade Brown wrote:

As per tagged nans, check for JavaScript tagged NaN optimization. Essentially, the tag of the NaN (i.e. the mantissa) is interpreted as a pointer. Obviously, this is a very advanced use case, probably not worth Python guaranteeing such behavior. Here is one article: https://brionv.com/log/2018/05/17/javascript-engine-internals-nan-boxing/

You are talking about an *internal implementation detail* in the C code of the Javascript engine, not a Javascript language feature. There is no Javascript API for the JS programmer to perform NAN boxing or to encode pointers inside the 51 payload bits of NANs.

Aside from the extra complexity, which may or may not pay off in speed improvements, the downside of NAN boxing is the serious security hole that if you can introduce an arbitrary NAN value into a JS primitive value, you get a pointer to arbitrary memory and can use that to get up to all sorts of shenanigans.

To avoid that security hole, JS has to normalise all incoming NANs to a single canonical NAN (thus, losing any possibility of user code making use of NAN payloads).

In CPython's case, the interpreter uses pointers as object references, not the payload bits of a NAN. Jython and IronPython use whatever the JVM and .Net CLR use, which probably isn't NANs either.

So while NAN boxing is a clever use of NAN payloads, it's not really relevant here. Python code doesn't have a notion of pointers to arbitrary addresses, but if it did, user code probably wouldn't have to manipulate the payload bits of a NAN float object to get one.

I never said it was, he specifically said as an aside for a book he was writing. He said he hadn't heard of code using it, so I provided an example

You are talking about an *internal implementation detail* in the C code

of the Javascript engine, not a Javascript language feature. There is no Javascript API for the JS programmer to perform NAN boxing or to encode pointers inside the 51 payload bits of NANs.

I never claimed there was, just that that was a use case of tagged nans, was common for JS engine implementers to use, and indeed was a use case in which inspecting the payload bits and having unique nan values was relevant.

Imagine that a Python program would use a `libc` binding (for example, C-types) to interface with such an engine. It would have to be able to differentiate. Obviously, there are good reasons Python doesn't support it, and people shouldn't grow to expect it, and this isn't really relevant to the discussion (insofar as the PEP proposed doesn't specify that 'inf' and 'nan' be treated as singletones, just as default builtins).

This would become relevant, if, say Python 4.0 migrated 'inf' and 'nan' to builtin names (like True and False). If that happened, a 'nan' singleton wouldn't make sense unless you had 2**53 of them, so code like:

x is nan

Would be a flawed formulation

On Sun, Sep 13, 2020 at 8:57 PM Steven D'Aprano steve@pearwood.info wrote:

On Sat, Sep 12, 2020 at 08:16:36PM -0400, Cade Brown wrote:

As per tagged nans, check for JavaScript tagged NaN optimization. Essentially, the tag of the NaN (i.e. the mantissa) is interpreted as a pointer. Obviously, this is a very advanced use case, probably not worth Python guaranteeing such behavior. Here is one article:

https://brionv.com/log/2018/05/17/javascript-engine-internals-nan-boxing/

You are talking about an *internal implementation detail* in the C code of the Javascript engine, not a Javascript language feature. There is no Javascript API for the JS programmer to perform NAN boxing or to encode pointers inside the 51 payload bits of NANs.

Aside from the extra complexity, which may or may not pay off in speed improvements, the downside of NAN boxing is the serious security hole that if you can introduce an arbitrary NAN value into a JS primitive value, you get a pointer to arbitrary memory and can use that to get up to all sorts of shenanigans.

To avoid that security hole, JS has to normalise all incoming NANs to a single canonical NAN (thus, losing any possibility of user code making use of NAN payloads).

In CPython's case, the interpreter uses pointers as object references, not the payload bits of a NAN. Jython and IronPython use whatever the JVM and .Net CLR use, which probably isn't NANs either.

So while NAN boxing is a clever use of NAN payloads, it's not really relevant here. Python code doesn't have a notion of pointers to arbitrary addresses, but if it did, user code probably wouldn't have to manipulate the payload bits of a NAN float object to get one.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/54RN6H... Code of Conduct: http://python.org/psf/codeofconduct/

On Mon, Sep 14, 2020 at 11:05 AM Cade Brown brown.cade@gmail.com wrote:

This would become relevant, if, say Python 4.0 migrated 'inf' and 'nan' to builtin names (like True and False). If that happened, a 'nan' singleton wouldn't make sense unless you had 2**53 of them, so code like:

x is nan

Would be a flawed formulation

Nobody's suggesting that they become keywords representing singletons, which is what True and False are. (At least, I don't think so.) What's being proposed is simply a builtin name that has a value of float("inf"). People don't write "x is 1.5" and they shouldn't use "x is inf". It doesn't matter that there are multiple bit patterns that represent nan; you shouldn't be doing this even when there's only one bit pattern for the value. Yes, sometimes people do this with small integers, and in CPython it may work ("x is 5" will usually be true for any integer 5), but it's just as buggy there and I don't think that's particularly relevant.

(How often do people even use "x is True"?)

ChrisA

Hence why I said 'would', 'if' etc. And it was brought up/suggested, having singletons. It does naturally flow from having a built-in (much like having singletons for booleans does):

sugggesting that one reason that they were made keywords is that it's

useful for them to be singletons, which is much harder to do (or at least use consistently) if the names can be reassigned. But these float special values can't be singletons anyway -- they could come from anywhere, so you really don't want to have people doing:

(to be honest, to me it does make sense to have 'inf' singletons, but not for 'nan's. but, neither is part of the PEP).

'inf' is a very special value, and there are only 2 infinite floats (inf, -inf). Having a singleton is useful also perhaps as a memory optimization (i.e. whenever creating a float from C, check if it is infinite, and if so, return a new reference to the global inf/-inf variable).

Again, this is not part of the PEP, so I don't think we want to spend much time discussing whether they should be singletons. For now, the answer seems to be: no Thanks, ---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

On Sun, Sep 13, 2020 at 10:19 PM Chris Angelico rosuav@gmail.com wrote:

On Mon, Sep 14, 2020 at 11:05 AM Cade Brown brown.cade@gmail.com wrote:

This would become relevant, if, say Python 4.0 migrated 'inf' and 'nan'

to builtin names (like True and False). If that happened, a 'nan' singleton wouldn't make sense unless you had 2**53 of them, so code like:

x is nan

Would be a flawed formulation

Nobody's suggesting that they become keywords representing singletons, which is what True and False are. (At least, I don't think so.) What's being proposed is simply a builtin name that has a value of float("inf"). People don't write "x is 1.5" and they shouldn't use "x is inf". It doesn't matter that there are multiple bit patterns that represent nan; you shouldn't be doing this even when there's only one bit pattern for the value. Yes, sometimes people do this with small integers, and in CPython it may work ("x is 5" will usually be true for any integer 5), but it's just as buggy there and I don't think that's particularly relevant.

(How often do people even use "x is True"?)

ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/PAQQ4J... Code of Conduct: http://python.org/psf/codeofconduct/

On Mon, Sep 14, 2020 at 12:16:54PM +1000, Chris Angelico wrote:

(How often do people even use "x is True"?)

Alas, that is a common idiom. For example:

https://stackoverflow.com/questions/50816182/pep-8-comparison-to-true-should...

It's possibly less common than it used to be now that PEP 8 warns against it:

https://www.python.org/dev/peps/pep-0008/

and so linters flag it. But I've seen it used by beginners and experienced programmers alike.

There is some justification for it in the case that you want to test specifically for the True instance, being much shorter than:

arbitrary_object == 1 and type(arbitrary_object) is bool

but many people have a mental blindspot and write:

if flag is True: true_condition() else: false_condition()

even when they know full well that flag is guaranteed to be a bool.

I know that sometimes I catch myself doing the same. I recently rediscovered some old Pascal code I write in the 1990s and sure enough, I have "if flag == true" in that too.

Of course we all know that it should be written:

if flag is True is True: ...

except I never know when to stop:

if flag is True is True is True is True is True is True is ...

*wink*

To me it seems like a useful shortcut that means:

x == True and type(x) == bool

But, as you say, it is best to just let the Python interpreter treat it as a boolean (i.e. within an `if`, it is converted automatically)

Now, I am thinking it would actually be *bad* to have the CPython implementation define `inf` singletons -- imagine a 3rd party library (for example, sympy) that defines '==' for new types:

```

from sympy import oo oo == inf

True

oo is inf

False ``` Again, it would be useful for a shortcut: `x is inf` is the same as `x == inf and type(x) == float`, but with 3rd party libraries I don't think it's something good to rely on.

On Mon, Sep 14, 2020, 12:05 AM Steven D'Aprano steve@pearwood.info wrote:

On Mon, Sep 14, 2020 at 12:16:54PM +1000, Chris Angelico wrote:

(How often do people even use "x is True"?)

Alas, that is a common idiom. For example:

https://stackoverflow.com/questions/50816182/pep-8-comparison-to-true-should...

It's possibly less common than it used to be now that PEP 8 warns against it:

https://www.python.org/dev/peps/pep-0008/

and so linters flag it. But I've seen it used by beginners and experienced programmers alike.

There is some justification for it in the case that you want to test specifically for the True instance, being much shorter than:

`arbitrary_object == 1 and type(arbitrary_object) is bool`

but many people have a mental blindspot and write:

`if flag is True: true_condition() else: false_condition()`

even when they know full well that flag is guaranteed to be a bool.

I know that sometimes I catch myself doing the same. I recently rediscovered some old Pascal code I write in the 1990s and sure enough, I have "if flag == true" in that too.

Of course we all know that it should be written:

`if flag is True is True: ...`

except I never know when to stop:

`if flag is True is True is True is True is True is True is ...`

*wink*

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/45KTF4... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 12, 2020 at 02:09:11PM -1000, David Mertz wrote:

On Sat, Sep 12, 2020, 2:02 PM Steven D'Aprano steve@pearwood.info wrote:

In general though, Python doesn't support generating the full range of NANs with payloads directly.

It's possible I've missed something, but certainly not the top 20 languages are libraries that might come to mind.

Alas, NAN payloads have been under-utilized. It has been a vicious circle: programming languages have, in general, not supported setting the payload, or any consistent meaning for them, so people don't use the feature, so programming languages don't support it, so people don't use it, and so on...

But back in the early 1990s, when IEEE-754 was brand new, one of the first platforms to support it was Apple's SANE (Standard Apple Numerics Environment), and they not only supported NAN payloads, but defined standard meanings for them. So Apple's maths libraries would parse strings like "NAN(123)" (by memory) and return the NAN with payload 123. Printing NANs would display the payload. And you could use the payload information to help debug what failed, e.g.

NANSQRT = 1 # invalid square root NANADD = 2 # invalid addition, e.g. INF + (-INF)

But when Apple moved their SANE maths libraries out of software and into the Motorola floating point chip, that was all lost.

On 9/12/20 8:48 PM, Paul Bryan wrote:

I meant to ask, why is nan not comparable? Even:

math.nan == math.nan

False

It's the IEEE definition of nan, a nan will compare unequal to ALL values, even another nan.

It is also neither greater than or less than any value.

On Sat, Sep 12, 2020 at 05:48:30PM -0700, Paul Bryan wrote:

I meant to ask, why is nan not comparable? Even:

math.nan == math.nan

False

It is worth explaining why the IEEE-754 standards committee agreed to make NANs unequal to everything.

"It is not possible to specify a fixed-size arithmetic type that satisfies all of the properties of real arithmetic that we know and love. The 754 committee has to decide to bend or break some of them. This is guided by some pretty simple principles:

1. When we can, we match the behavior of real arithmetic.

2. When we can't, we try to make the violations as predictable and as easy to diagnose as possible."

https://stackoverflow.com/a/1573715

Having NANs compare equal to NANs would lead to nonsensical results like:

* sqrt(-2) == sqrt(-3) * 0.0/0.0 == acos(2.0) * infinity - infinity == log(-1.0)

NANs represent an exceptional state in your calculation. Some wag once argued that these are exceptional cases because, no matter what we choose to do, someone will take exception to it. NANs are no exception (pun intended) and I think that there is no single right answer.

I think that it might be worth re-iterating the value of NaN & Infinity – there are times when you are performing calculations and need to flag where something problematic happened but __not__ stop. Examples would be real-time control where you could discard a bad result but still need to move on to the next or operations on large chunks of data where you need to perform the calculation on every element and then discard/ignore the invalid results, (this is almost certainly why Pandas makes a lot of use of NaN).

The value of NaN is that it is a valid input to any float point calculation but will always result in a NaN out. Therefore if something goes wrong at any point in your calculation you can log that a problem occurred and carry on without loosing the fact that the result is invalid. (This is much liked in the functional programming world).

One of the many things that I like about python is that it is easy to create a NaN _with `float(‘nan’)`_ if you wish to generate & return an invalid value (it is a nightmare to do in C – e.g. for when a sensor hasn’t replied but you still have to complete the read & reply process).

Personally I also like the IEEE INF & -INF values with their grantee that regardless of bit length they can never be an actual value – I have had a lot of issues with code that returns a clipped valid value when it really means overflow. I have even argued that it would be great to have a `int(‘nan’)` & ‘int(‘inf’)` values to be able to mirror these useful properties.

I am ambivalent on the need to have constants for these special values but would like to argue strongly against any constructs such as infinity = 1e300, etc., after all would this still be an overflow on a machine that supported decimal128 (overflow at 1e6145) & Octuple (256 bit) overflow at about 1.62e78913 values and in the future 512/1024 bit floats – I love the cross platform support of python.

Sorry to be teaching grandma to suck eggs.

Steve Barnes

On Sat, Sep 12, 2020 at 5:05 PM Steven D'Aprano steve@pearwood.info wrote:

On Sat, Sep 12, 2020 at 12:56:25PM -0700, Christopher Barker wrote:

Is there any guarantee in Python or the C spec, or the IEEE spec that,

e.g.:

1e10000 would create an Inf value, rather than an error of some sort?

IEEE-754 requires that float literals overflow to infinity.

sure, which means that, e.g. 1e100 * 1e300 would overflow to Inf.

But that doesn't say anything about interpreting a literal. I don't if C libs necessarily parse:

xxEyy

and then do xx * 10**yy, which would be an overflow, or if they do something more direct, in which case, they *could* note that the value is not representable and raise an error.

So that's what I'm wondering -- is there a standard that says the a too-large literal should overflow, and therefgor create and inf, rather than being an error.

by the way, this behavior is not consistent with python, which will give an error, rather than returning inf when the same operation overflows:

In [22]: math.pow(10, 1000)

--------------------------------------------------------------------------- OverflowError Traceback (most recent call last) <ipython-input-22-6efc9a2b034c> in <module> ----> 1 math.pow(10, 1000)

OverflowError: math range error

So in Python, at least, interpreting the literal is not the same as computing the pow().

-CHB

I don't have a source for this (I cannot find a copy of the IEEE-754 standard except behind paywalls) but I have a very strong memory of either Tim Peters and Mark Dickinson stating this, and I believe them. (If either of them are reading this, please confirm or deny.)

And there's still NaN -- any way to get that with a literal?

If you have an INF, then you can generate a NAN with `INF - INF`.

In general though, Python doesn't support generating the full range of NANs with payloads directly.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/LX5XVA... Code of Conduct: http://python.org/psf/codeofconduct/

On Sat, Sep 12, 2020 at 05:37:23PM -0700, Christopher Barker wrote:

On Sat, Sep 12, 2020 at 5:05 PM Steven D'Aprano steve@pearwood.info wrote:

IEEE-754 requires that float literals overflow to infinity.

sure, which means that, e.g. 1e100 * 1e300 would overflow to Inf.

But that doesn't say anything about interpreting a literal. I don't if C libs necessarily parse:

Sorry, I didn't explain correctly. What I attempted, but failed, to say is that the standard requires that if the float literal cannot be represented as a numeric value because it would overflow, then it should be interpreted as an infinity.

So `1e300` can be represented as a double precision float, so that's what you get, but `1e1000` cannot be, it overflows, so you get infinity instead.

This doesn't mean that the standard requires the parser to read the mantissa and exponent separately and actually perform a multiplication and power.

I expect that the standard will require *correctly rounded* results. So for example, this literal rounds down to the largest possible finite float:

py> 1.7976931348623158e+308 1.7976931348623157e+308

but this literal rounds up to infinity:

py> 1.7976931348623159e+308 inf

because the closest representable binary number to 1.79...159e+308 would overflow the available bits.

So that's what I'm wondering -- is there a standard that says the a too-large literal should overflow, and therefgor create and inf, rather than being an error.

Yep, that's what I'm saying :-)

Or at least tried to say.

Cade Brown writes:

When I read "1e1000" or such a number it doesn't strike me as infinite

As Steven points out, it's an overflow, and IEEE *but not Python* is clear about that. In fact, none of the actual infinities I've tried (1.0 / 0.0 and math.tan(math.pi / 2.0)) result in values of inf. The former raises ZeroDivisionError and the latter gives the finite value 1.633123935319537e+16.

Steven D'Aprano writes:

Nobody is recommending that [as] the best way to create an infinity

Is there a way to create an infinity in base Python, though? You can create infs (with 1e1000 or 2e308 or 1e1000000000 or 2e200 * 2e200), but those aren't infinities, those are overflows. All the examples in this thread, and infs in general Pythonic practice, are expressions which have well-defined mathematical values, but overflow the range of floats, and *inf doesn't tell you which mathematical value*, or indeed even admit that "YMMV".[1]

It's not obvious to me why 1e309 and 9e308 should be equal in Python -- 1e309 - 9e308 is close to the largest number you can express as a Python float! The point is that inf arithmetic only makes sense if carefully analyzed in the context, not just of the application but even down to the specific calculation.

I assume that IEEE did some sort of generic analysis and concluded that mathematical infinities and overflows map to inf, mathematical undefineds map to nan, overflows map to inf, and underflows map to zero. But, as a large set of values, perhaps we'd be better off with overflow treated as nan? Or perhaps overflow should be rounded to sys.float_info.max since all finite values are closer to that than they are to infinity? Or maybe overflow should be a different kind of thing, where some operations produce another overflow (adding a positive finite number, multiplying by a number with magnitude > 1), while others produce nans (overflow - overflow, as with infs, but also overflow - positive_finite). Maybe all nans should raise by default.

Using something like 1e1000 [...] is a fall back

I prefer to think of it as being honest: this isn't infinity, this is overflow -- and the way Python treats infs, here be Dragons, all bets are off, "magic is loose in the world", and anything can happen.

Footnotes: [1] Float 0 also makes little sense for the same reason, but somehow "anything close enough to zero 'is' zero" doesn't bother me as much as "anything a little bit bigger than 1e308 'is' infinite" does. I guess it should ....

On Sun, Sep 13, 2020 at 8:10 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

As Steven points out, it's an overflow, and IEEE *but not Python* is clear about that. In fact, none of the actual infinities I've tried (1.0 / 0.0 and math.tan(math.pi / 2.0)) result in values of inf. The former raises ZeroDivisionError and the latter gives the finite value 1.633123935319537e+16.

probably because math.pi is not exact, either -- I'm pretty sure Python is wrapping the C lib for math.tan, so that's not a Python issue.

And I don't think that IEEE 754 requires that all overflows go to inf. Apparently it does for literals (thanks Steven), but you can, at the language / library level choose to raise exceptions for overflow.

In the Python world, numpy lets the user control the error handling:

https://numpy.org/doc/stable/reference/generated/numpy.seterr.html

by default, overflow warns, but results in an infinity:

In [47]: arr = np.array([1e300])

In [48]: arr * 1e300

<ipython-input-48-598041e50dbb>:1: RuntimeWarning: overflow encountered in multiply arr * 1e300 Out[48]: array([inf])

So you get a warning, but still the infinity.

But if you change the error handling, you can get an Exception.

In [49]: np.seterr(over='raise')

Out[49]: {'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}

In [50]: arr * 1e300

--------------------------------------------------------------------------- FloatingPointError Traceback (most recent call last) <ipython-input-50-598041e50dbb> in <module> ----> 1 arr * 1e300

FloatingPointError: overflow encountered in multiply

Python used to have an interface to the fpectl system, presumably to do things like this, but it was removed in py3.7:

""" The fpectl module has been removed. It was never enabled by default, never worked correctly on x86-64, and it changed the Python ABI in ways that caused unexpected breakage of C extensions. (Contributed by Nathaniel J. Smith in bpo-29137.) """

As you've noticed, Python itself has limited use for Inf and NaN values, which is probably why it got as far as it did with the really bad support before 2.6. But these special values are used in external code called from Python (including numpy), an so it's helpful to have good support for them in Python anyway.

Which brings up a point about the Singleton idea (yes, I know that no ine is proposing making singletons of inf and nan at this point anyway): while the Python float type *could* enforce that they be singletons (essentially like interning the special values), you can get them in other types, from other sources, so I think you wouldn't want them to be singletons. Example: numpy float32 type:

In [52]: np32inf = np.float32('inf')

In [53]: type(np32inf)

Out[53]: numpy.float32

In [54]: math.inf == np32inf

Out[54]: True

An "is" check would never work there.

that mathematical infinities and overflows map to inf, mathematical

undefineds map to nan, overflows map to inf, and underflows map to zero. But, as a large set of values, perhaps we'd be better off with overflow treated as nan?

IEEE 754 is a very practical standard -- it was well designed, and is widely used and successful. It is not perfect, and in certain use cases, it may not be the best choice. But it's a really good idea to keep to that standard by default.

If we wanted Python to allow users more control, we could add an fp error handling context, maybe like numpy's -- but I don't think there's been much demand for it.

Note that one of the key things about numpy, and why its defaults are different, is that it does array-oriented math. Most people do not want their entire computation to be stopped if only one value in an array under- or over-flows, etc.

That may apply in pure python to things like comprehensions, but most folks doing heavy duty number crunching are using numpy anyway.

Anyway, the only thing on the table now is putting a couple names in the builtin namespace.

-CHB

Christopher Barker writes:

On Sun, Sep 13, 2020 at 8:10 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

As Steven points out, it's an overflow, and IEEE *but not Python* is clear about that. In fact, none of the actual infinities I've tried (1.0 / 0.0 and math.tan(math.pi / 2.0)) result in values of inf. The former raises ZeroDivisionError and the latter gives the finite value 1.633123935319537e+16.

probably because math.pi is not exact, either -- I'm pretty sure Python is wrapping the C lib for math.tan, so that's not a Python issue.

The issue is that Python doesn't produce true infinities as far as I know, so "inf" is a very poor name for float('inf') in builtins. I wince at math.inf as well, but at least there it feels like "this is an IEEE 754 feature that Python uses".

In the Python world, numpy lets the user control the error handling:

Not every 1_000_000 line module needs to be a builtin. We're talking about adding these names to the builtins, what NumPy does is irrelevant (and NumPy already has its own inf).

As you've noticed, Python itself has limited use for Inf and NaN values, which is probably why it got as far as it did with the really bad support before 2.6. But these special values are used in external code called from Python (including numpy), an so it's helpful to have good support for them in Python anyway.

What's ungood about "from math import inf, nan"? Or "from numpy import inf, nan"?

IEEE 754 is a very practical standard -- it was well designed, and is widely used and successful. It is not perfect, and in certain use cases, it may not be the best choice. But it's a really good idea to keep to that standard by default.

I agree, but Python doesn't. It raises on some infs (generally speaking, true infinities), and returns inf on others (generally speaking, overflows). To change that you need to bring in C extensions.

Note that one of the key things about numpy, and why its defaults are different, is that it does array-oriented math. Most people do not want their entire computation to be stopped if only one value in an array under- or over-flows, etc.

That's fine, but Python doesn't give you that. In floats, 0.0 is not true 0, it's the set of all underflow results plus true 0. So by your argument, in float arithmetic, we should not have ZeroDivisionErrors. But we do raise them.

Anyway, the only thing on the table now is putting a couple names in the builtin namespace.

Which is why I've tried pretty hard to stick to those aspects of inf and nan that are builtin to Python or available directly with "from math import inf, nan".

On 9/14/20 12:34 PM, Stephen J. Turnbull wrote:

That's fine, but Python doesn't give you that. In floats, 0.0 is not true 0, it's the set of all underflow results plus true 0. So by your argument, in float arithmetic, we should not have ZeroDivisionErrors. But we do raise them.

Actually, with IEEE, 0.0 should be all numbers, when rounded to the nearest representation give the value 0.

When we get to very small numbers, the 'sub-normals', we get numbers that are really some integral value times 2 to some negative power (I think it is something like 2 to the -1022 for the standard 64 bit floats). This says that as we approach 0, we have sequence of evenly spaced representable values, 3*2**-1022, 2*2**-1022, 1*2**-1022, 0*2**-1022

Thus the concept of "Zero" makes sense as the nearest representable value.

Now, as been mentioned, "Infinity", doesn't match this concept, unless you do something like define it as it represents a value just above the highest represntable value, but that doesn't match the name.

On Tue, Sep 15, 2020 at 3:45 AM Richard Damon Richard@damon-family.org wrote:

On 9/14/20 12:34 PM, Stephen J. Turnbull wrote:

That's fine, but Python doesn't give you that. In floats, 0.0 is not true 0, it's the set of all underflow results plus true 0. So by your argument, in float arithmetic, we should not have ZeroDivisionErrors. But we do raise them.

Actually, with IEEE, 0.0 should be all numbers, when rounded to the nearest representation give the value 0.

When we get to very small numbers, the 'sub-normals', we get numbers that are really some integral value times 2 to some negative power (I think it is something like 2 to the -1022 for the standard 64 bit floats). This says that as we approach 0, we have sequence of evenly spaced representable values, 3*2**-1022, 2*2**-1022, 1*2**-1022, 0*2**-1022

Thus the concept of "Zero" makes sense as the nearest representable value.

Now, as been mentioned, "Infinity", doesn't match this concept, unless you do something like define it as it represents a value just above the highest represntable value, but that doesn't match the name.

In mathematics, "infinity" isn't a value. One cannot actually perform arithmetic on it. But in mathematics, it's perfectly acceptable to talk about stupid big numbers and do arithmetic that wouldn't ever be possible with full precision (eg calculating the last digits of Graham's Number). Mathematicians are also perfectly happy to work with transcendental numbers as actual values, and, again, to perform arithmetic on them even though we don't know the exact value.

Computers can't do that. So we have a set of rules for approximating mathematics in ways that are useful, even though they're not true representations of real numbers. (Something something "practicality beats purity" yada yada.) That's why we have to deal with rounding errors, that's why we have to work with trig functions that aren't perfectly precise, etc, etc. They're *good enough* for real-world usage. And that's why we need "Infinity" to be a value, of sorts. If you wish, every IEEE float can be taken to represent a range of values (all those that would round to it), but that's not often useful (although AIUI that's how Python chooses to give a shorter display for many numbers - it finds some short number that would have the same representation and prints that). Much more practical to treat them as actual numbers, including that 0.0 really does mean the additive identity (and is the sole representation of it), even though this leads to contradictions of sorts:

x = 1.0 x != 0.0 # True y = float(1<<53) x + y == y # True # Subtract y from both sides, proving 1.0 == 0.0

If you want to define infinity as any particular value, you're going to get into a contradiction somewhere sooner or later. But its behaviour in IEEE arithmetic is well defined and *useful* even without trying to make everything make sense.

Let's stick to discussing whether "inf" (or "Infinity") should become a new builtin name, and let the IEEE experts figure out whether infinity is a thing or not :)

ChrisA

Chris Angelico writes:

In mathematics, "infinity" isn't a value. One cannot actually perform arithmetic on it.

That's a rather controversial opinion. Even intuitionist mathematicians perform arithmetic on infinities; they just find it very distasteful that they have to do so.

Computers can't do that.

This is flat wrong. It is very *inefficient* to have *current* computers perform arithmetic on infinities (transcendental quantities, etc), but Stephen Wolfram (and his net worth) would be very surprised at your statement.

So we have a set of rules for approximating mathematics in ways that are useful,

Exactly right.

even though they're not true representations of real numbers.

That's imprecise. They are *true* representations of certain real numbers, but they are also *approximate* representations of other real numbers, and the function from value to representation is not invertible (as an extended-real-valued function).

They're *good enough* for real-world usage.

True for *finite* IEEE floats. Very controversial for inf and nan, and especially for Python's rather inconsistent API for IEEE float.

And that's why we need "Infinity" to be a value, of sorts.

That's a non sequitur. First, inf already *is a value* in Python, it has a name both as str and repr, and it even has a pseudo-literal name in the math module. It just doesn't have a pseudo-literal name in builtins (and that is all that is on offer here -- the proponents say over and over again that they're not asking for keywords, and haven't proposed a literal name for -inf yet). Second, that the connected spaces of positive and negative reals which have float representations are usefully approximated by floats does not imply that the isolated points of -infinity, zero, and +infinity are equally useful approximations. They may be, but my strongly-held opinion is "nah."

In practice, the justification for inf and nan is that in an inner loop it's extremely inefficient to raise and handle exceptions every time an overflow, underflow, or domain error occurs. So you substitute inf or nan as appropriate, keep looping until done, and then work with the presumed accurate finite values that remain. *inf and nan don't need to have names to serve such functions*, let alone names in builtins.

If you want to define infinity as any particular value, you're going to get into a contradiction somewhere sooner or later. But its behaviour in IEEE arithmetic is well defined and *useful* even without trying to make everything make sense.

As Ben Rudiak-Gould shows, the behavior of operations whose results do not have representation as Python floats is anything but "well-defined".

Let's stick to discussing whether "inf" (or "Infinity") should become a new builtin name

Definitely not "Infinity" (unless you want to go for a keyword, in which case a capitalized keyword in the tradition of None, False, and True seems appropriate). We've used "inf" for (a) decade(s), we don't need a new name.

As for builtins, "what's so ungood about 'from math import inf, nan'?" I don't see a persuasive answer to that.

On Tue, Sep 15, 2020 at 5:17 PM Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Chris Angelico writes:

In mathematics, "infinity" isn't a value. One cannot actually perform arithmetic on it.

That's a rather controversial opinion. Even intuitionist mathematicians perform arithmetic on infinities; they just find it very distasteful that they have to do so.

Computers can't do that.

This is flat wrong. It is very *inefficient* to have *current* computers perform arithmetic on infinities (transcendental quantities, etc), but Stephen Wolfram (and his net worth) would be very surprised at your statement.

Hang on hang on, transcendental quantities are still finite. It may take an infinite sequence to fully calculate them, but they are finite values. We're not talking about pi here, we're talking about treating "infinity" as a value. You can certainly do arithmetic on pi.

ChrisA

Chris Angelico writes:

Hang on hang on, transcendental quantities are still finite. It may take an infinite sequence to fully calculate them, but they are finite values. We're not talking about pi here, we're talking about treating "infinity" as a value. You can certainly do arithmetic on pi.

Arithmetic, yes, I guess, but not correct trigonometry:

from math import tan, pi tan(pi/2)

1.633123935319537e+16

That's infinitely wrong in mathematics! Or 293 orders of magnitude, if you prefer IEEE, where inf == 1e309 :-)

On Mon, Sep 14, 2020 at 9:36 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Christopher Barker writes:

IEEE 754 is a very practical standard -- it was well designed, and is widely used and successful. It is not perfect, and in certain use

cases, it

may not be the best choice. But it's a really good idea to keep to that standard by default.

I feel the same way; I really wish Python was better about following IEEE 754.

I agree, but Python doesn't. It raises on some infs (generally

speaking, true infinities), and returns inf on others (generally speaking, overflows).

It seems to be very inconsistent. From testing just now:

* math.lgamma(0) raises "ValueError: math domain error"

* math.exp(1000) raises "OverflowError: math range error"

* math.e ** 1000 raises "OverflowError: (34, 'Result too large')"

* (math.e ** 500) * (math.e ** 500) returns inf

* sum([1e308, 1e308]) returns inf

* math.fsum([1e308, 1e308]) raises "OverflowError: intermediate overflow in fsum"

* math.fsum([1e308, inf, 1e308]) returns inf

* math.fsum([inf, 1e308, 1e308]) raises "OverflowError: intermediate overflow in fsum"

* float('1e999') returns inf

* float.fromhex('1p1024') raises "OverflowError: hexadecimal value too large to represent as a float"

I get the impression that little planning has gone into this. There's no consistency in the OverflowError messages. 1./0. raises ZeroDivisionError which isn't a subclass of OverflowError. lgamma(0) raises a ValueError, which isn't even a subclass of ArithmeticError. The function has a pole at 0 with a well-defined two-sided limit of +inf. If it isn't going to return +inf then it ought to raise ZeroDivisionError, which should obviously be a subclass of OverflowError.

Because of the inconsistent handling of overflow, many functions aren't even monotonic. exp(2*x) returns a float for x <= 709.782712893384, raises OverflowError for 709.782712893384 < x <= 8.98846567431158e+307, and returns a float for x > 8.98846567431158e+307.

1./0. is not a true infinity. It's the reciprocal of a number that may have underflowed to zero. It's totally inconsistent to return inf for 1/1e-323 and raise an exception for 1/1e-324, as Python does.

Thanks so much Ben for documenting all these examples. I've been frustrated by the inconsistencies, but hasn't realized all of those you note.

It would be a breaking change, but I'd really vastly prefer if almost all of those OverflowErrors and others were simply infinities. That's much closer to the spirit of IEEE-754.

The tricky case is 1./0. Division is such an ordinary operation, and it's so easy to get zero in a variable accidentally. That one still feels like an exception, but yes 1/1e-323 vs. 1/1e-324 would them remain a sore spot.

Likewise, a bunch of operations really should be NaN that are exceptions now.

On Mon, Sep 14, 2020, 5:26 PM Ben Rudiak-Gould benrudiak@gmail.com wrote:

On Mon, Sep 14, 2020 at 9:36 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Christopher Barker writes:

IEEE 754 is a very practical standard -- it was well designed, and is widely used and successful. It is not perfect, and in certain use

cases, it

may not be the best choice. But it's a really good idea to keep to that standard by default.

I feel the same way; I really wish Python was better about following IEEE 754.

I agree, but Python doesn't. It raises on some infs (generally

speaking, true infinities), and returns inf on others (generally speaking, overflows).

It seems to be very inconsistent. From testing just now:

math.lgamma(0) raises "ValueError: math domain error"

math.exp(1000) raises "OverflowError: math range error"

math.e ** 1000 raises "OverflowError: (34, 'Result too large')"

(math.e ** 500) * (math.e ** 500) returns inf

sum([1e308, 1e308]) returns inf

math.fsum([1e308, 1e308]) raises "OverflowError: intermediate overflow

in fsum"

math.fsum([1e308, inf, 1e308]) returns inf

math.fsum([inf, 1e308, 1e308]) raises "OverflowError: intermediate

overflow in fsum"

float('1e999') returns inf

float.fromhex('1p1024') raises "OverflowError: hexadecimal value too

large to represent as a float"

I get the impression that little planning has gone into this. There's no consistency in the OverflowError messages. 1./0. raises ZeroDivisionError which isn't a subclass of OverflowError. lgamma(0) raises a ValueError, which isn't even a subclass of ArithmeticError. The function has a pole at 0 with a well-defined two-sided limit of +inf. If it isn't going to return +inf then it ought to raise ZeroDivisionError, which should obviously be a subclass of OverflowError.

Because of the inconsistent handling of overflow, many functions aren't even monotonic. exp(2*x) returns a float for x <= 709.782712893384, raises OverflowError for 709.782712893384 < x <= 8.98846567431158e+307, and returns a float for x > 8.98846567431158e+307.

1./0. is not a true infinity. It's the reciprocal of a number that may have underflowed to zero. It's totally inconsistent to return inf for 1/1e-323 and raise an exception for 1/1e-324, as Python does.

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TXEZTN... Code of Conduct: http://python.org/psf/codeofconduct/

On Tue, 15 Sep 2020 at 06:54, David Mertz mertz@gnosis.cx wrote:

Thanks so much Ben for documenting all these examples. I've been frustrated by the inconsistencies, but hasn't realized all of those you note.

It would be a breaking change, but I'd really vastly prefer if almost all of those OverflowErrors and others were simply infinities. That's much closer to the spirit of IEEE-754.

The tricky case is 1./0. Division is such an ordinary operation, and it's so easy to get zero in a variable accidentally. That one still feels like an exception, but yes 1/1e-323 vs. 1/1e-324 would them remain a sore spot.

We need to remember that a significant number of Python users don't have any idea what IEE-754 is, and have never heard of a NaN (and possibly even of infinity as a number). Those people are *far* better served by being told "you made a mistake" in the form of an exception, rather than via a weird numeric value that doesn't work how they expect and doesn't even look like a number when they print it.

Paul

We need to remember that a significant number of Python users don't have any idea what IEE-754 is, and have never heard of a NaN (and possibly even of infinity as a number). Those people are *far* better served by being told "you made a mistake" in the form of an exception, rather than via a weird numeric value that doesn't work how they expect and doesn't even look like a number when they print it.

Paul

My feeling is that both viewpoints can be satisfied by having a context whereby if USE_IEEE_SPECIAL_VALUES (to pick a random name) is False (the default) such operations will raise an exception but if it is True INF, -INF or NaN is returned (ideally with some debug output – this would be in the spirit of the IEEE Signalling NaN).

Steve Barnes

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity, NegativeInfinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

If 1/0 is infinity (because 0 goes into 1 infinity times), is 2/0 2*inifnity (because 0 goes into 2 2 times more than into 1)

A proper CAS really is advisable. FWIU, different CAS have different outputs for the above problem (most just disregard the scalar because it's infinity so who care if that cancels out later).

Where are the existing test cases for arithemetic calculations with (scalar times) IEEE-754 int, +inf, or -inf as the output?

On Tue, Sep 15, 2020 at 1:54 AM David Mertz mertz@gnosis.cx wrote:

Thanks so much Ben for documenting all these examples. I've been frustrated by the inconsistencies, but hasn't realized all of those you note.

It would be a breaking change, but I'd really vastly prefer if almost all of those OverflowErrors and others were simply infinities. That's much closer to the spirit of IEEE-754.

The tricky case is 1./0. Division is such an ordinary operation, and it's so easy to get zero in a variable accidentally. That one still feels like an exception, but yes 1/1e-323 vs. 1/1e-324 would them remain a sore spot.

Likewise, a bunch of operations really should be NaN that are exceptions now.

On Mon, Sep 14, 2020, 5:26 PM Ben Rudiak-Gould benrudiak@gmail.com wrote:

On Mon, Sep 14, 2020 at 9:36 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Christopher Barker writes:

IEEE 754 is a very practical standard -- it was well designed, and is widely used and successful. It is not perfect, and in certain use

cases, it

may not be the best choice. But it's a really good idea to keep to

that

standard by default.

I feel the same way; I really wish Python was better about following IEEE 754.

I agree, but Python doesn't. It raises on some infs (generally

speaking, true infinities), and returns inf on others (generally speaking, overflows).

It seems to be very inconsistent. From testing just now:

math.lgamma(0) raises "ValueError: math domain error"

math.exp(1000) raises "OverflowError: math range error"

math.e ** 1000 raises "OverflowError: (34, 'Result too large')"

(math.e ** 500) * (math.e ** 500) returns inf

sum([1e308, 1e308]) returns inf

math.fsum([1e308, 1e308]) raises "OverflowError: intermediate overflow

in fsum"

math.fsum([1e308, inf, 1e308]) returns inf

math.fsum([inf, 1e308, 1e308]) raises "OverflowError: intermediate

overflow in fsum"

float('1e999') returns inf

float.fromhex('1p1024') raises "OverflowError: hexadecimal value too

large to represent as a float"

I get the impression that little planning has gone into this. There's no consistency in the OverflowError messages. 1./0. raises ZeroDivisionError which isn't a subclass of OverflowError. lgamma(0) raises a ValueError, which isn't even a subclass of ArithmeticError. The function has a pole at 0 with a well-defined two-sided limit of +inf. If it isn't going to return +inf then it ought to raise ZeroDivisionError, which should obviously be a subclass of OverflowError.

Because of the inconsistent handling of overflow, many functions aren't even monotonic. exp(2*x) returns a float for x <= 709.782712893384, raises OverflowError for 709.782712893384 < x <= 8.98846567431158e+307, and returns a float for x > 8.98846567431158e+307.

1./0. is not a true infinity. It's the reciprocal of a number that may have underflowed to zero. It's totally inconsistent to return inf for 1/1e-323 and raise an exception for 1/1e-324, as Python does.

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TXEZTN... Code of Conduct: http://python.org/psf/codeofconduct/

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GLUX5W... Code of Conduct: http://python.org/psf/codeofconduct/

On Mon, Oct 12, 2020 at 5:06 AM Wes Turner wes.turner@gmail.com wrote:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity, NegativeInfinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

If 1/0 is infinity (because 0 goes into 1 infinity times), is 2/0 2*inifnity (because 0 goes into 2 2 times more than into 1)

If you try to treat "infinity" as an actual number, you're inevitably going to run into paradoxes. Consider instead: 1/x tends towards +∞ as x tends towards 0 (if x starts out positive), therefore we consider that 1/0 is +∞. By that logic, the limit of 2/0 is the exact same thing. It's still not a perfect system, and division by zero is always going to cause problems, but it's far less paradoxical if you don't try to treat 2/0 as different from 1/0 :)

BTW, you're technically correct, in that 2/0 would be the same as 2 * (whatever 1/0 is), but that's because 2*x tends towards +∞ as x tends towards +∞, meaning that 2*∞ is also ∞.

ChrisA

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

And:

```# Given that: inf / inf = 1

# When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2

# If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1

# I think it's specious to argue that there are infinity solutions; that axioms of symbolic mathematics do not apply because infinity ```

This is relevant to the (now-forked) main thread if the plan is to return inf/-inf/+inf instead of raising ZeroDivisionError; so I'm replying to the main thread.

On Sun, Oct 11, 2020, 4:10 PM Chris Angelico rosuav@gmail.com wrote: On Mon, Oct 12, 2020 at 5:06 AM Wes Turner wes.turner@gmail.com wrote:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity,

NegativeInfinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

If 1/0 is infinity (because 0 goes into 1 infinity times), is 2/0 2*inifnity (because 0 goes into 2 2 times more than into 1)

If you try to treat "infinity" as an actual number, you're inevitably going to run into paradoxes. Consider instead: 1/x tends towards +∞ as x tends towards 0 (if x starts out positive), therefore we consider that 1/0 is +∞. By that logic, the limit of 2/0 is the exact same thing. It's still not a perfect system, and division by zero is always going to cause problems, but it's far less paradoxical if you don't try to treat 2/0 as different from 1/0 :)

BTW, you're technically correct, in that 2/0 would be the same as 2 * (whatever 1/0 is), but that's because 2*x tends towards +∞ as x tends towards +∞, meaning that 2*∞ is also ∞.

ChrisA

On Sun, Oct 11, 2020 at 2:03 PM Wes Turner wes.turner@gmail.com wrote:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity, NegativeInfinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

A proper CAS really is advisable. FWIU, different CAS have different outputs for the above problem (most just disregard the scalar because it's infinity so who care if that cancels out later).

Where are the existing test cases for arithemetic calculations with (scalar times) IEEE-754 int, +inf, or -inf as the output?

On Tue, Sep 15, 2020 at 1:54 AM David Mertz mertz@gnosis.cx wrote:

Likewise, a bunch of operations really should be NaN that are exceptions now.

On Mon, Sep 14, 2020, 5:26 PM Ben Rudiak-Gould benrudiak@gmail.com wrote:

On Mon, Sep 14, 2020 at 9:36 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Christopher Barker writes:

cases, it

may not be the best choice. But it's a really good idea to keep to

that

standard by default.

I feel the same way; I really wish Python was better about following IEEE 754.

I agree, but Python doesn't. It raises on some infs (generally

speaking, true infinities), and returns inf on others (generally speaking, overflows).

It seems to be very inconsistent. From testing just now:

math.lgamma(0) raises "ValueError: math domain error"

math.exp(1000) raises "OverflowError: math range error"

math.e ** 1000 raises "OverflowError: (34, 'Result too large')"

(math.e ** 500) * (math.e ** 500) returns inf

sum([1e308, 1e308]) returns inf

math.fsum([1e308, 1e308]) raises "OverflowError: intermediate overflow

in fsum"

math.fsum([1e308, inf, 1e308]) returns inf

math.fsum([inf, 1e308, 1e308]) raises "OverflowError: intermediate

overflow in fsum"

float('1e999') returns inf

float.fromhex('1p1024') raises "OverflowError: hexadecimal value too

large to represent as a float"

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TXEZTN... Code of Conduct: http://python.org/psf/codeofconduct/

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GLUX5W... Code of Conduct: http://python.org/psf/codeofconduct/

On Mon, Oct 12, 2020 at 8:07 AM Wes Turner wes.turner@gmail.com wrote:

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

On what basis? If you start by assuming that infinity is a number, then sure, you're going to deduce that double it must be a greater number. But you're just concluding your own assumption, not proving anything.

And:

`inf / inf = 1`

Is that the case?

from math import inf inf / inf

nan

# When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2

# If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1

# I think it's specious to argue that there are infinity solutions; that axioms of symbolic mathematics do not apply because infinity

Once again, you start by assuming that infinity is a number, and that you can divide by it (which is what happens when you "solve for x" by removing the infinities). You can't prove something by first assuming it.

"Infinity" isn't a number. In the IEEE 754 system, it is a value, but it's still not a number (although it's distinct from Not A Number, just to confuse everyone). In mathematics, it's definitely not an actual number or value.

ChrisA

On 10/11/20 5:04 PM, Wes Turner wrote:

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

And:

`inf / inf = 1 # When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2 # If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1 # I think it's specious to argue that there are infinity solutions; that axioms of symbolic mathematics do not apply because infinity`

Treating inf as any other number because it works out 'symbolically' is one of the recipes that allow you to prove that 1 == 2, thus symbolic math needs to work with certain preconditions that avoid the generation of 'numbers' like infinity into the system (or somewhat related, avoid a divide by 0)

Indeed, perhaps virtual particles can never divide by zero and thus the observed laws of thermodynamic systems are preserved.

Would you please be so kind as to respond in the main thread so that this is one consecutive thread?

No, 2 times something is greater than something. Something over something

is 1. If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.

Which of these are you arguing should fail if Python changes to returning [+/-]inf instead of raising ZeroDivisionError?

assert 1 / 0 != 2 / 0 assert 2*inf > inf assert inf / inf == 1

On Sun, Oct 11, 2020 at 5:41 PM Richard Damon Richard@damon-family.org wrote:

On 10/11/20 5:04 PM, Wes Turner wrote:

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

And:

`inf / inf = 1 # When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2 # If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1 # I think it's specious to argue that there are infinity solutions; that axioms of symbolic mathematics do not apply because infinity`

Treating inf as any other number because it works out 'symbolically' is one of the recipes that allow you to prove that 1 == 2, thus symbolic math needs to work with certain preconditions that avoid the generation of 'numbers' like infinity into the system (or somewhat related, avoid a divide by 0)

-- Richard Damon _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SQNY5W... Code of Conduct: http://python.org/psf/codeofconduct/

On 10/11/20 5:47 PM, Wes Turner wrote:

Indeed, perhaps virtual particles can never divide by zero and thus the observed laws of thermodynamic systems are preserved.

Would you please be so kind as to respond in the main thread so that this is one consecutive thread?

`No, 2 times something is greater than something. Something over something is 1. If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.`

Which of these are you arguing should fail if Python changes to returning [+/-]inf instead of raising ZeroDivisionError?

`assert 1 / 0 != 2 / 0 assert 2*inf > inf assert inf / inf == 1`

All of them will fail. n / 0 is inf or -inf depending on whether n is positive or negative (and I believe 0/0 is NaN)

n * inf is inf, for all n > 0

inf / inf in NaN (if I remember right).

infinity is NOT just a number that behaves like any finite number.

Maybe you should look into the rules for transfinite mathematics, a lot of the rules that apply for finite mathematics don't work when you allow for non-finite numbers.

Note, that for example you last example, the answer of Z+ is correct, as Z+ does NOT include infinity, so the case where x is infinity, is outside the domain Z, or even R.

Also note, the the Axioms like the Division Axiom apply to the domains of Finite numbers, and not all of them apply when you get Infinities. This is just like some properties in the Real do not apply when you move to the Complex plane.

On Sun, Oct 11, 2020 at 5:41 PM Richard Damon <Richard@damon-family.org mailto:Richard@damon-family.org> wrote:

`On 10/11/20 5:04 PM, Wes Turner wrote: > So you're arguing that the scalar is irrelevant? > That `2*inf == inf`? > > I disagree because: > ```2*inf > inf``` > > And: > > ```# Given that: > inf / inf = 1 > > # When we solve for symbol x: > 2*inf*x = inf > 2*x = 1 > x = 1/2 > > # If we discard the scalar instead: > 2*inf*x = inf > inf*x = inf > x = 1 > > # I think it's specious to argue that there are infinity solutions; > that axioms of symbolic mathematics do not apply because infinity > ``` > Treating inf as any other number because it works out 'symbolically' is one of the recipes that allow you to prove that 1 == 2, thus symbolic math needs to work with certain preconditions that avoid the generation of 'numbers' like infinity into the system (or somewhat related, avoid a divide by 0) -- Richard Damon _______________________________________________ Python-ideas mailing list -- python-ideas@python.org <mailto:python-ideas@python.org> To unsubscribe send an email to python-ideas-leave@python.org <mailto:python-ideas-leave@python.org> https://mail.python.org/mailman3/lists/python-ideas.python.org/ <https://mail.python.org/mailman3/lists/python-ideas.python.org/> Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SQNY5WFVPRPWXRZ7FW3H3RUGM3UCLCCL/ <https://mail.python.org/archives/list/python-ideas@python.org/message/SQNY5WFVPRPWXRZ7FW3H3RUGM3UCLCCL/> Code of Conduct: http://python.org/psf/codeofconduct/ <http://python.org/psf/codeofconduct/>`

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4VUULY... Code of Conduct: http://python.org/psf/codeofconduct/

On Sun, Oct 11, 2020 at 05:47:44PM -0400, Wes Turner wrote:

No, 2 times something is greater than something. Something over something is 1.

Define "something". Define "times" (multiplication). Define "greater than". Define "over" (division).

And while you are at it, don't forget to define what you mean by "infinity". Do you mean potential infinity, actual infinity, Absolute infinity, aleph and beth numbers, omegas, or something else?

https://www.cut-the-knot.org/WhatIs/WhatIsInfinity.shtml

I am not being facetious. Getting your definitions right is vital if you wish to avoid error, and to avoid miscommunication. Change the definitions, and you change the meaning of everything said.

(1) In the so-called "real numbers", there is no such thing as infinity. Since there is no such thing as infinity, infinity is not "something" that can be multiplied or divided, or added or subtracted. In the Real number system, there is no coherent way of doing arithmetic on "infinity". "Two times infinity" is meaningless.

In the real numbers, there's no sensible way of doing arithmetic with "infinity" without leading to contradiction.

Informally, infinity in the Real number system is a process that never completes, so doing twice as much doesn't take any longer.

(2) Mathematicians have created at least two extensions to the Real number line which do include at least one infinity. It is possible to construct a coherent system that is not self-contradictory by including either a pair of plus and minus infinity, or just a single unsigned infinity:

https://en.wikipedia.org/wiki/Extended_real_number_line

https://en.wikipedia.org/wiki/Projectively_extended_real_line

But in doing so, we have to give up certain "common sense" properties of finite numbers. For example, with only a single infinity, infinity is both greater than everything, and less than (more negative) than everything. We lose a coherent definition of "greater than".

Even in the extended number lines, two times infinity is just infinity, and infinity divided by infinity is not coherent and cannot be defined in any sensible way.

The IEEE-754 standard, and consequently Python floats, closely models the extended real number line.

(3) In the *cardinal numbers*, there is something called infinity. Or rather, there are an *infinite number* of infinities, starting with the smallest, aleph-0, which represents the cardinality of the integers, i.e. what people usually mean when they think of infinity.

Even in the cardinal numbers, two times infinity (aleph-0) is just aleph-0; however you might be pleased to know that two to the power of aleph-0 is aleph-1.

Arithmetic with infinite cardinal numbers is strange.

https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel

(4) In other extensions of the real numbers, such as hyperreal and surreal numbers, we can work with various different kinds of infinities (and infinitesimals).

For example, in the surreal numbers, we can do arithmetic on infinities, and you will be gratified, I am sure, that twice infinity is different from plain old infinity. In the language of the surreals:

2ω = ω + ω ≠ ω

(That's an omega symbol, not ∞.)

Unfortunately, the surreals are very different from the commonsense world of the real numbers we know and love. For starters, they form a tree, not a line. You cannot reach ω by starting at 0 and adding 1 repeatedly. (ω is not the successor of any ordinal number.) Consequently there are other infinite numbers like ω-1 that are less than infinity but cannot be reached by counting upwards from zero but only by counting down from infinity.

And of course, in the surreal numbers, there are an infinity of ever-growing infinities: not just ω+1 and 2ω but ω^2 and ω^ω and so on, all of which are "bigger than infinity".

https://en.wikipedia.org/wiki/Surreal_number

All very fascinating I am sure, but I don't think that we should be trying to emulate the surreal numbers as part of float.

Thank you for the overview. It seems as though this community will also look to IEEE-754 (the IEEE Standard for Floating-Point Arithmetic) for Reals and also Infinity.

Should Python raise exceptions for Integers or [Complex] Fractions involving Infinity, or should Python assume that IEEE-754 is the canonical source of truth about infinity?

IEEE-754 (2019), a closed standard, costs $100 for the PDF. I'll Ctrl-F for 'infinity' in the Wikipedia article:

https://en.wikipedia.org/wiki/IEEE_754 :

Exception handling

The standard defines five exceptions, each of which returns a default value and has a corresponding status flag that is raised when the exception occurs.[e] No other exception handling is required, but additional non-default alternatives are recommended (see § Alternate exception handling). The five possible exceptions are:

- Invalid operation: mathematically undefined, e.g., the square root of a
negative number. By default, returns qNaN.

- Division by zero: an operation on finite operands gives an exact
infinite result, e.g., 1/0 or log(0). By default, returns ±infinity.

- Overflow: a result is too large to be represented correctly (i.e., its
exponent with an unbounded exponent range would be larger than emax). By default, returns ±infinity for the round-to-nearest modes (and follows the rounding rules for the directed rounding modes).

- Underflow: a result is very small (outside the normal range) and is
inexact. By default, returns a subnormal or zero (following the rounding rules). Inexact: the exact (i.e., unrounded) result is not representable exactly. By default, returns the correctly rounded result.

It appears that IEEE-754 implemented as per the binary spec could not represent more complex assessments of inifnity:

As with IEEE 754-1985, the biased-exponent field is filled with all 1 bits

to indicate either infinity (trailing significand field = 0) or a NaN (trailing significand field ≠ 0). For NaNs, quiet NaNs and signaling NaNs are distinguished by using the most significant bit of the trailing significand field exclusively,[d] and the payload is carried in the remaining bits.

json5 extends the JSON to support IEEE-754 +-inf (and +-0, which can also be used to indicate 1D directionality sans magnitude).

Presumably, in the IEEE-754 view of the world,

from math import inf, nan assert type(inf) == float assert isinstance(inf, float) assert float("inf") == inf

assert inf / inf == nan

assert inf / 0 == inf # currently: ZeroDivisionError

assert (x/0) < ((x+1e-10)/0) # where x>0 (x in Z+) # Not possible; Python is not a CAS

https://en.wikipedia.org/wiki/List_of_computer_algebra_systems doesn't have a column for a "Surreal Numbers" or "non-Float handling of infinity".

https://en.wikipedia.org/wiki/Quantum_field_theory#Infinities_and_renormaliz... deals with Infinities; which have curently been removed.

inf**inf

On Sun, Oct 11, 2020 at 9:07 PM Steven D'Aprano steve@pearwood.info wrote:

On Sun, Oct 11, 2020 at 05:47:44PM -0400, Wes Turner wrote:

No, 2 times something is greater than something. Something over something is 1.

Define "something". Define "times" (multiplication). Define "greater than". Define "over" (division).

And while you are at it, don't forget to define what you mean by "infinity". Do you mean potential infinity, actual infinity, Absolute infinity, aleph and beth numbers, omegas, or something else?

https://www.cut-the-knot.org/WhatIs/WhatIsInfinity.shtml

I am not being facetious. Getting your definitions right is vital if you wish to avoid error, and to avoid miscommunication. Change the definitions, and you change the meaning of everything said.

(1) In the so-called "real numbers", there is no such thing as infinity. Since there is no such thing as infinity, infinity is not "something" that can be multiplied or divided, or added or subtracted. In the Real number system, there is no coherent way of doing arithmetic on "infinity". "Two times infinity" is meaningless.

In the real numbers, there's no sensible way of doing arithmetic with "infinity" without leading to contradiction.

Informally, infinity in the Real number system is a process that never completes, so doing twice as much doesn't take any longer.

(2) Mathematicians have created at least two extensions to the Real number line which do include at least one infinity. It is possible to construct a coherent system that is not self-contradictory by including either a pair of plus and minus infinity, or just a single unsigned infinity:

https://en.wikipedia.org/wiki/Extended_real_number_line

https://en.wikipedia.org/wiki/Projectively_extended_real_line

But in doing so, we have to give up certain "common sense" properties of finite numbers. For example, with only a single infinity, infinity is both greater than everything, and less than (more negative) than everything. We lose a coherent definition of "greater than".

Even in the extended number lines, two times infinity is just infinity, and infinity divided by infinity is not coherent and cannot be defined in any sensible way.

The IEEE-754 standard, and consequently Python floats, closely models the extended real number line.

(3) In the *cardinal numbers*, there is something called infinity. Or rather, there are an *infinite number* of infinities, starting with the smallest, aleph-0, which represents the cardinality of the integers, i.e. what people usually mean when they think of infinity.

Even in the cardinal numbers, two times infinity (aleph-0) is just aleph-0; however you might be pleased to know that two to the power of aleph-0 is aleph-1.

Arithmetic with infinite cardinal numbers is strange.

https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel

(4) In other extensions of the real numbers, such as hyperreal and surreal numbers, we can work with various different kinds of infinities (and infinitesimals).

For example, in the surreal numbers, we can do arithmetic on infinities, and you will be gratified, I am sure, that twice infinity is different from plain old infinity. In the language of the surreals:

`2ω = ω + ω ≠ ω`

(That's an omega symbol, not ∞.)

Unfortunately, the surreals are very different from the commonsense world of the real numbers we know and love. For starters, they form a tree, not a line. You cannot reach ω by starting at 0 and adding 1 repeatedly. (ω is not the successor of any ordinal number.) Consequently there are other infinite numbers like ω-1 that are less than infinity but cannot be reached by counting upwards from zero but only by counting down from infinity.

And of course, in the surreal numbers, there are an infinity of ever-growing infinities: not just ω+1 and 2ω but ω^2 and ω^ω and so on, all of which are "bigger than infinity".

https://en.wikipedia.org/wiki/Surreal_number

All very fascinating I am sure, but I don't think that we should be trying to emulate the surreal numbers as part of float.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MI4HG6... Code of Conduct: http://python.org/psf/codeofconduct/

(OT: https://en.wikipedia.org/wiki/Banach%E2%80%93Tarski_paradox#Obtaining_infini...

Using the Banach–Tarski paradox, it is possible to obtain k copies of a

ball in the Euclidean n-space from one, for any integers n ≥ 3 and k ≥ 1, i.e. a ball can be cut into k pieces so that each of them is equidecomposable to a ball of the same size as the original.

... in *Euclidean n-space*.

https://en.wikipedia.org/wiki/Holographic_principle#Limit_on_information_den... :

This suggests that matter itself cannot be subdivided infinitely many

times and there must be an ultimate level of fundamental particles. As the degrees of freedom of a particle are the product of all the degrees of freedom of its sub-particles, were a particle to have infinite subdivisions into lower-level particles, the degrees of freedom of the original particle would be infinite, violating the maximal limit of entropy density.

[Microscopic] black holes do deal with infinity in certain regards.)

On Sun, Oct 11, 2020 at 10:40 PM Wes Turner wes.turner@gmail.com wrote:

Thank you for the overview. It seems as though this community will also look to IEEE-754 (the IEEE Standard for Floating-Point Arithmetic) for Reals and also Infinity.

Should Python raise exceptions for Integers or [Complex] Fractions involving Infinity, or should Python assume that IEEE-754 is the canonical source of truth about infinity?

IEEE-754 (2019), a closed standard, costs $100 for the PDF. I'll Ctrl-F for 'infinity' in the Wikipedia article:

https://en.wikipedia.org/wiki/IEEE_754 :

Exception handling

The standard defines five exceptions, each of which returns a default value and has a corresponding status flag that is raised when the exception occurs.[e] No other exception handling is required, but additional non-default alternatives are recommended (see § Alternate exception handling). The five possible exceptions are:

- Invalid operation: mathematically undefined, e.g., the square root of a
negative number. By default, returns qNaN.

- Division by zero: an operation on finite operands gives an exact
infinite result, e.g., 1/0 or log(0). By default, returns ±infinity.

- Overflow: a result is too large to be represented correctly (i.e., its
exponent with an unbounded exponent range would be larger than emax). By default, returns ±infinity for the round-to-nearest modes (and follows the rounding rules for the directed rounding modes).

- Underflow: a result is very small (outside the normal range) and is
inexact. By default, returns a subnormal or zero (following the rounding rules). Inexact: the exact (i.e., unrounded) result is not representable exactly. By default, returns the correctly rounded result.

It appears that IEEE-754 implemented as per the binary spec could not represent more complex assessments of inifnity:

As with IEEE 754-1985, the biased-exponent field is filled with all 1 bits

to indicate either infinity (trailing significand field = 0) or a NaN (trailing significand field ≠ 0). For NaNs, quiet NaNs and signaling NaNs are distinguished by using the most significant bit of the trailing significand field exclusively,[d] and the payload is carried in the remaining bits.

json5 extends the JSON to support IEEE-754 +-inf (and +-0, which can also be used to indicate 1D directionality sans magnitude).

Presumably, in the IEEE-754 view of the world,

from math import inf, nan assert type(inf) == float assert isinstance(inf, float) assert float("inf") == inf

assert inf / inf == nan

assert inf / 0 == inf # currently: ZeroDivisionError

assert (x/0) < ((x+1e-10)/0) # where x>0 (x in Z+) # Not possible; Python is not a CAS

https://en.wikipedia.org/wiki/List_of_computer_algebra_systems doesn't have a column for a "Surreal Numbers" or "non-Float handling of infinity".

https://en.wikipedia.org/wiki/Quantum_field_theory#Infinities_and_renormaliz... deals with Infinities; which have curently been removed.

inf**inf

On Sun, Oct 11, 2020 at 9:07 PM Steven D'Aprano steve@pearwood.info wrote:

On Sun, Oct 11, 2020 at 05:47:44PM -0400, Wes Turner wrote:

No, 2 times something is greater than something. Something over

something

is 1.

Define "something". Define "times" (multiplication). Define "greater than". Define "over" (division).

And while you are at it, don't forget to define what you mean by "infinity". Do you mean potential infinity, actual infinity, Absolute infinity, aleph and beth numbers, omegas, or something else?

https://www.cut-the-knot.org/WhatIs/WhatIsInfinity.shtml

I am not being facetious. Getting your definitions right is vital if you wish to avoid error, and to avoid miscommunication. Change the definitions, and you change the meaning of everything said.

(1) In the so-called "real numbers", there is no such thing as infinity. Since there is no such thing as infinity, infinity is not "something" that can be multiplied or divided, or added or subtracted. In the Real number system, there is no coherent way of doing arithmetic on "infinity". "Two times infinity" is meaningless.

In the real numbers, there's no sensible way of doing arithmetic with "infinity" without leading to contradiction.

Informally, infinity in the Real number system is a process that never completes, so doing twice as much doesn't take any longer.

(2) Mathematicians have created at least two extensions to the Real number line which do include at least one infinity. It is possible to construct a coherent system that is not self-contradictory by including either a pair of plus and minus infinity, or just a single unsigned infinity:

https://en.wikipedia.org/wiki/Extended_real_number_line

https://en.wikipedia.org/wiki/Projectively_extended_real_line

But in doing so, we have to give up certain "common sense" properties of finite numbers. For example, with only a single infinity, infinity is both greater than everything, and less than (more negative) than everything. We lose a coherent definition of "greater than".

Even in the extended number lines, two times infinity is just infinity, and infinity divided by infinity is not coherent and cannot be defined in any sensible way.

The IEEE-754 standard, and consequently Python floats, closely models the extended real number line.

(3) In the *cardinal numbers*, there is something called infinity. Or rather, there are an *infinite number* of infinities, starting with the smallest, aleph-0, which represents the cardinality of the integers, i.e. what people usually mean when they think of infinity.

Even in the cardinal numbers, two times infinity (aleph-0) is just aleph-0; however you might be pleased to know that two to the power of aleph-0 is aleph-1.

Arithmetic with infinite cardinal numbers is strange.

https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel

(4) In other extensions of the real numbers, such as hyperreal and surreal numbers, we can work with various different kinds of infinities (and infinitesimals).

For example, in the surreal numbers, we can do arithmetic on infinities, and you will be gratified, I am sure, that twice infinity is different from plain old infinity. In the language of the surreals:

`2ω = ω + ω ≠ ω`

(That's an omega symbol, not ∞.)

Unfortunately, the surreals are very different from the commonsense world of the real numbers we know and love. For starters, they form a tree, not a line. You cannot reach ω by starting at 0 and adding 1 repeatedly. (ω is not the successor of any ordinal number.) Consequently there are other infinite numbers like ω-1 that are less than infinity but cannot be reached by counting upwards from zero but only by counting down from infinity.

And of course, in the surreal numbers, there are an infinity of ever-growing infinities: not just ω+1 and 2ω but ω^2 and ω^ω and so on, all of which are "bigger than infinity".

https://en.wikipedia.org/wiki/Surreal_number

All very fascinating I am sure, but I don't think that we should be trying to emulate the surreal numbers as part of float.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MI4HG6... Code of Conduct: http://python.org/psf/codeofconduct/

On 12/10/20 3:44 pm, Wes Turner wrote:

[Microscopic] black holes do deal with infinity in certain regards.)

Not really. General relativity predicts that matter will collapse into a point of zero size and infinite density inside a black hole. But that's more likely to mean that GR is wrong under such extreme conditions, than to mean that there's actually a singularity at the centre of a black hole.

In any case, this doesn't have anything to do with the present discussion. You can't use physics to prove things about maths, or vice versa.

On Mon, Oct 12, 2020, 1:43 AM Greg Ewing greg.ewing@canterbury.ac.nz wrote:

On 12/10/20 3:44 pm, Wes Turner wrote:

[Microscopic] black holes do deal with infinity in certain regards.)

Not really. General relativity predicts that matter will collapse into a point of zero size and infinite density inside a black hole. But that's more likely to mean that GR is wrong under such extreme conditions, than to mean that there's actually a singularity at the centre of a black hole.

Whether scalar times infinity is relevant to describing the progression of a black hole / wormhole / whitehole is something that cannot be assessed without symbolic mathematics; which IEEE-754 (and the proposed Python implementation of IEEE-754's alternative to ZeroDivisionError) cannot solve for.

In any case, this doesn't have anything to do with the present discussion. You can't use physics to prove things about maths, or vice versa.

OT: There are certainly applications for (scalar times) float and non-float infinity. ZeroDivisionError may be more desirable than attempting to build a CAS in stdlib; or even handling non-float math.inf in stdlib.

Notably, the https://en.wikipedia.org/wiki/Bekenstein_bound is limited to certainly less than infinity, but there is disagreement in other forums over whether black holes have an event horizon or an apparent horizon.

"the absence of event horizons mean that there are no black holes – in

the sense of regimes from which light can't escape to infinity."

https://en.wikipedia.org/wiki/Event_horizon

"It's just inf; the other terms are then irrelevant" is insufficient for many applications.

Where are the standard library and third-party tests that catch ZeroDivisionError?

Something this be an appropriate migration strategy for implementing IEEE-754 inf/+inf/-inf:

from __future__ import floatinfinity

On Sun, Oct 11, 2020 at 11:04 PM Wes Turner wes.turner@gmail.com wrote:

(and the proposed Python implementation of IEEE-754's alternative to ZeroDivisionError)

Is anyone actually proposing this (i.e. changing how Python handles division by zero, or other float exceptions) ?

There IS a proposal on the table to add math.inf and math.nan to builtins, which is the only one I know about (and I'm supposed to help write a PEP for, which has stalled out) But while there has been a bunch of discussion, I don't know that anyone has actually proposed anything.

But if so -- could whoever it is write the proposal down? (Ideally in a new thread)

this be an appropriate migration strategy for implementing IEEE-754 inf/+inf/-inf:

from __future__ import floatinfinity

FWIW, if a change were to be made, I'd rather it be some kind of float error handling context: either a global setting, like numpy's, or a context manager. With, of course, the default behavior just like it's been forever.

-CHB

On Mon, 12 Oct 2020 at 07:23, Christopher Barker pythonchb@gmail.com wrote:

FWIW, if a change were to be made, I'd rather it be some kind of float error handling context: either a global setting, like numpy's, or a context manager. With, of course, the default behavior just like it's been forever.

You can have both a global setting and then a context manager for altering it, although it would need to be thread-safe. I would certainly make use of an option to have exceptions instead of nans.

I did suggest something similar at some point and was pointed to fpectl: https://docs.python.org/2/library/fpectl.html I haven't looked in any detail but I suspect that making fpectl work on all platforms is not really viable: this should probably be handled within the interpreter rather than at the FPU level (although that could be used as an optimisation for some platforms).

-- Oscar

On Sun, Oct 11, 2020, 9:07 PM Steven D'Aprano

Oh... So you're one of those who believe the Continuum Hypothesis :-).

I was going to mention Surreal Numbers also, but I see you touched on it.

David Mertz writes:

On Sun, Oct 11, 2020, 9:07 PM Steven D'Aprano

Oh... So you're one of those who believe the Continuum Hypothesis :-).

As any good defense lawyer can tell you, you don't need to believe something to use it to prove something else. :-)

I was going to mention Surreal Numbers also, but I see you touched on it.

As far as what Steven discussed, the ordinal numbers have the same properties (except I've never heard of ω-1 in a discussion of ordinals, but it should work I think). (Maybe the surreals are constructed from the ordinals as the reals are constrcuted from the cardinals?)

On Mon, 12 Oct 2020 at 14:51, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

As far as what Steven discussed, the ordinal numbers have the same properties (except I've never heard of ω-1 in a discussion of ordinals, but it should work I think).

I don't think it does. The ordinals are based on the idea of *orderings* of (potentially infinite) sets. So ω+1 is the ordinal of something like

1, 2, 3, ... 1

Addition is basically "bunging the second sequence at the end of the first". There's no obvious meaning for subtraction in the general sense here - you can't take a chunk off the end of an infinite sequence. And in particular, I can't think of an ordering that would map to ω-1 - it would have to be an ordering that, when you added a single item after it, would be equivalent to ω, which has no "end", so where did that item you added go?

(Apologies for the informal explanations, my set theory and logic courses were many years ago, and while my pedantry cries out for precision, my laziness prevents me from looking up the specifics :-))

Paul

On Mon, Oct 12, 2020, 9:50 AM Stephen J. Turnbull

As far as what Steven discussed, the ordinal numbers have the same properties (except I've never heard of ω-1 in a discussion of ordinals, but it should work I think). (Maybe the surreals are constructed from the ordinals as the reals are constructed from the cardinals?)

Not exactly. Cauchy sequences define Reals in terms of countably infinite sequences of Rational numbers. The Surreals are defined by binary trees of every transfinite length (not only countably infinite).

Basically, the right-most branch in the Surreal tree is simply the Cantor ordinals. But in the other paths were encounter things like infinitesimals and ω-1. Subtraction and division wind up defined over Surreals, unlike for regular transfinite ordinals.

"If formulated in von Neumann–Bernays–Gödel set theory https://en.m.wikipedia.org/wiki/Von_Neumann%E2%80%93Bernays%E2%80%93G%C3%B6del_set_theory, the surreal numbers are a universal ordered field in the sense that all other ordered fields, such as the rationals, the reals, the rational functions https://en.m.wikipedia.org/wiki/Rational_function, the Levi-Civita field https://en.m.wikipedia.org/wiki/Levi-Civita_field, the superreal numbers https://en.m.wikipedia.org/wiki/Superreal_number, and the hyperreal numbers https://en.m.wikipedia.org/wiki/Hyperreal_number, can be realized as subfields of the surreals. The surreals also contain all transfinite https://en.m.wikipedia.org/wiki/Transfinite_number ordinal numbers https://en.m.wikipedia.org/wiki/Ordinal_number; the arithmetic on them is given by the natural operations https://en.m.wikipedia.org/wiki/Ordinal_arithmetic#Natural_operations."

On 11/10/2020 22:47, Wes Turner wrote:

Indeed, perhaps virtual particles can never divide by zero and thus the observed laws of thermodynamic systems are preserved.

Would you please be so kind as to respond in the main thread so that this is one consecutive thread?

`No, 2 times something is greater than something. Something over something is 1. If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.`

Which of these are you arguing should fail if Python changes to returning [+/-]inf instead of raising ZeroDivisionError?

`assert 1 / 0 != 2 / 0 assert 2*inf > inf`

Both of them (assuming that they don't raise an exception).

`assert inf / inf == 1`

That should raise an exception; inf/inf is meaningless (just as division by zero is meaningless with finite numbers).

No offence Wes, but you are clearly not familiar with the subject of transfinite numbers as discovered by Cantor. I earnestly suggest you learn something about it before making statements which are - again, no offence intended, but frankly - nonsense. Transfinite numbers do not obey the same rules as finite numbers. Which can be counter-intuitive and take some getting used to, but ... that's the way it is. Best wishes Rob Cliffe

Thanks for your feedback Rob.

On Sun, Oct 18, 2020, 12:27 AM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:

On 11/10/2020 22:47, Wes Turner wrote:

Would you please be so kind as to respond in the main thread so that this is one consecutive thread?

No, 2 times something is greater than something. Something over something

is 1. If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.

assert 1 / 0 != 2 / 0 assert 2*inf > inf

Both of them (assuming that they don't raise an exception).

assert inf / inf == 1

That should raise an exception; inf/inf is meaningless (just as division by zero is meaningless with finite numbers).

No offence Wes, but you are clearly not familiar with the subject of transfinite numbers as discovered by Cantor. I earnestly suggest you learn something about it before making statements which are - again, no offence intended, but frankly - nonsense. Transfinite numbers do not obey the same rules as finite numbers. Which can be counter-intuitive and take some getting used to, but ... that's the way it is. Best wishes Rob Cliffe _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NKE6DE... Code of Conduct: http://python.org/psf/codeofconduct/

assert math.inf**0 == 1 assert math.inf**math.inf == math.inf

On Sun, Oct 18, 2020, 3:13 AM Wes Turner wes.turner@gmail.com wrote:

Thanks for your feedback Rob.

On Sun, Oct 18, 2020, 12:27 AM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:

On 11/10/2020 22:47, Wes Turner wrote:

Would you please be so kind as to respond in the main thread so that this is one consecutive thread?

No, 2 times something is greater than something. Something over something

is 1. If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.

assert 1 / 0 != 2 / 0 assert 2*inf > inf

Both of them (assuming that they don't raise an exception).

assert inf / inf == 1

That should raise an exception; inf/inf is meaningless (just as division by zero is meaningless with finite numbers).

No offence Wes, but you are clearly not familiar with the subject of transfinite numbers as discovered by Cantor. I earnestly suggest you learn something about it before making statements which are - again, no offence intended, but frankly - nonsense. Transfinite numbers do not obey the same rules as finite numbers. Which can be counter-intuitive and take some getting used to, but ... that's the way it is. Best wishes Rob Cliffe _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NKE6DE... Code of Conduct: http://python.org/psf/codeofconduct/

Its probably best to Carry on with the infinity constant discussion

On Sun, Oct 18, 2020, 3:26 AM Wes Turner wes.turner@gmail.com wrote:

assert math.inf**0 == 1 assert math.inf**math.inf == math.inf

On Sun, Oct 18, 2020, 3:13 AM Wes Turner wes.turner@gmail.com wrote:

Thanks for your feedback Rob.

On Sun, Oct 18, 2020, 12:27 AM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:

On 11/10/2020 22:47, Wes Turner wrote:

Would you please be so kind as to respond in the main thread so that this is one consecutive thread?

No, 2 times something is greater than something. Something over

something is 1. If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.

assert 1 / 0 != 2 / 0 assert 2*inf > inf

Both of them (assuming that they don't raise an exception).

assert inf / inf == 1

No offence Wes, but you are clearly not familiar with the subject of transfinite numbers as discovered by Cantor. I earnestly suggest you learn something about it before making statements which are - again, no offence intended, but frankly - nonsense. Transfinite numbers do not obey the same rules as finite numbers. Which can be counter-intuitive and take some getting used to, but ... that's the way it is. Best wishes Rob Cliffe _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NKE6DE... Code of Conduct: http://python.org/psf/codeofconduct/

On Sun, Oct 18, 2020 at 03:26:11AM -0400, Wes Turner wrote:

assert math.inf**0 == 1 assert math.inf**math.inf == math.inf

Wes, I don't understand what point you are trying to make here. Are you agreeing with that behaviour? Disagreeing? Thought it was so surprising that you can't imagine why it happens? Something else?

If you find a behaviour which is forbidden or contradicted by the documentation, then you should report it as a bug, but just demonstrating what the behaviour is with no context isn't helpful.

Please remember that the things which are blindingly obvious to you because you just thought them are not necessarily obvious to those of us who aren't inside your head :-)

Python's float INFs and NANs (mostly?) obey the rules of IEEE-754 arithmetic. Those rules are close to the rules for the extended Real number line, with a point at both positive and negative infinity.

These rules are not necessarily the same as the rules for transfinite arithmetic, or the projective number line with a single infinity, or arithmetic on cardinal numbers, or surreal numbers.

Each of these number systems have related, but slightly different, rules. For example, IEEE-754 has a single signed infinity and 2**INF is exactly equal to INF. But in transfinite arithmetic, 2**INF is strictly greater than INF (for every infinity):

2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3

and so on, with no limit. There is no greatest aleph, there is always a larger one.

Do you have a concrete suggestion you would like to make for a change or new feature for Python? If not, I suggest that this thread is going nowhere.

Thank you for the explanation. I have nothing more to add to this discussion

On Sun, Oct 18, 2020, 4:47 AM Steven D'Aprano steve@pearwood.info wrote:

On Sun, Oct 18, 2020 at 03:26:11AM -0400, Wes Turner wrote:

assert math.inf**0 == 1 assert math.inf**math.inf == math.inf

Wes, I don't understand what point you are trying to make here. Are you agreeing with that behaviour? Disagreeing? Thought it was so surprising that you can't imagine why it happens? Something else?

If you find a behaviour which is forbidden or contradicted by the documentation, then you should report it as a bug, but just demonstrating what the behaviour is with no context isn't helpful.

Please remember that the things which are blindingly obvious to you because you just thought them are not necessarily obvious to those of us who aren't inside your head :-)

Python's float INFs and NANs (mostly?) obey the rules of IEEE-754 arithmetic. Those rules are close to the rules for the extended Real number line, with a point at both positive and negative infinity.

These rules are not necessarily the same as the rules for transfinite arithmetic, or the projective number line with a single infinity, or arithmetic on cardinal numbers, or surreal numbers.

Each of these number systems have related, but slightly different, rules. For example, IEEE-754 has a single signed infinity and 2**INF is exactly equal to INF. But in transfinite arithmetic, 2**INF is strictly greater than INF (for every infinity):

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

and so on, with no limit. There is no greatest aleph, there is always a larger one.

Do you have a concrete suggestion you would like to make for a change or new feature for Python? If not, I suggest that this thread is going nowhere.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/U5WXW3... Code of Conduct: http://python.org/psf/codeofconduct/

Actually, where in the docs is it clarified which parts of IEEE-754 are obeyed by Python? Or where should this be clarified?

To my understanding (according to Wikipedia), IEEE-754 returns +- infinity for DivideByZeroError and for FloatOverflow.

...

It's a rare use case; but one use case where this matters could be code that is mutating and selecting (evolutionary algorithms) to evolve a **symbolic** function. It could be documented that Python code could be so permuted for infinity and never find the best fitting function due to this limit.

A vectorizable CAS (with support for variable axioms in order to support things like e.g. transfinite and surreal numbers) would be a better fit.

But that's way OT for (though likely an eventual tangential implication of) this discussion of a **float, IEEE-754*** infinity constant; so I'll stop talking now.

On Sun, Oct 18, 2020 at 12:28 PM Wes Turner wes.turner@gmail.com wrote:

Thank you for the explanation. I have nothing more to add to this discussion

On Sun, Oct 18, 2020, 4:47 AM Steven D'Aprano steve@pearwood.info wrote:

On Sun, Oct 18, 2020 at 03:26:11AM -0400, Wes Turner wrote:

assert math.inf**0 == 1 assert math.inf**math.inf == math.inf

Wes, I don't understand what point you are trying to make here. Are you agreeing with that behaviour? Disagreeing? Thought it was so surprising that you can't imagine why it happens? Something else?

If you find a behaviour which is forbidden or contradicted by the documentation, then you should report it as a bug, but just demonstrating what the behaviour is with no context isn't helpful.

Please remember that the things which are blindingly obvious to you because you just thought them are not necessarily obvious to those of us who aren't inside your head :-)

Python's float INFs and NANs (mostly?) obey the rules of IEEE-754 arithmetic. Those rules are close to the rules for the extended Real number line, with a point at both positive and negative infinity.

These rules are not necessarily the same as the rules for transfinite arithmetic, or the projective number line with a single infinity, or arithmetic on cardinal numbers, or surreal numbers.

Each of these number systems have related, but slightly different, rules. For example, IEEE-754 has a single signed infinity and 2**INF is exactly equal to INF. But in transfinite arithmetic, 2**INF is strictly greater than INF (for every infinity):

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

and so on, with no limit. There is no greatest aleph, there is always a larger one.

Do you have a concrete suggestion you would like to make for a change or new feature for Python? If not, I suggest that this thread is going nowhere.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/U5WXW3... Code of Conduct: http://python.org/psf/codeofconduct/

On Sun, Oct 18, 2020 at 9:49 AM Wes Turner wes.turner@gmail.com wrote:

Actually, where in the docs is it clarified which parts of IEEE-754 are obeyed by Python?

Not sure, but I think the answer is "Most places" -- that is, cPython depends on teh compiler, math library, and hardware, most of which these days are IEEE-754 compliant.

To my understanding (according to Wikipedia), IEEE-754 returns +- infinity

for DivideByZeroError and for FloatOverflow.

I think the answer is that IEEE-754 specifies that +- Inf be returned If a value is returned at all. That is, raising an Exception does not violate the standard, but returning any other value would.

And by the way, I think asking Python to do anything other than IEE-754 for floats would be a VERY heavy lift, and never get anywhere -- as above, most of it happens at lower levels than Python.

-CHB

...

It's a rare use case; but one use case where this matters could be code that is mutating and selecting (evolutionary algorithms) to evolve a **symbolic** function. It could be documented that Python code could be so permuted for infinity and never find the best fitting function due to this limit.

A vectorizable CAS (with support for variable axioms in order to support things like e.g. transfinite and surreal numbers) would be a better fit.

But that's way OT for (though likely an eventual tangential implication of) this discussion of a **float, IEEE-754*** infinity constant; so I'll stop talking now.

On Sun, Oct 18, 2020 at 12:28 PM Wes Turner wes.turner@gmail.com wrote:

Thank you for the explanation. I have nothing more to add to this discussion

On Sun, Oct 18, 2020, 4:47 AM Steven D'Aprano steve@pearwood.info wrote:

On Sun, Oct 18, 2020 at 03:26:11AM -0400, Wes Turner wrote:

assert math.inf**0 == 1 assert math.inf**math.inf == math.inf

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

and so on, with no limit. There is no greatest aleph, there is always a larger one.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/U5WXW3... Code of Conduct: http://python.org/psf/codeofconduct/

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ODANBE... Code of Conduct: http://python.org/psf/codeofconduct/

Oops, I messed up. (Thanks David for pointing that out.)

On Sun, Oct 18, 2020 at 07:45:40PM +1100, Steven D'Aprano wrote:

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

I conflated what I was thinking:

# note the change in comparison 2**aleph_0 > aleph_0 2**aleph_1 > aleph_1 2**aleph_2 > aleph_2 ...

which I think is correct regardless of your position on the Continuum Hypothesis (David, care to comment?), with this:

2**aleph_0 = aleph_1 2**aleph_1 = aleph_2 2**aleph_2 = aleph_3 ...

which is only true if the Continuum Hypothesis is true, and then wrote down something which was complete nonsense. Sorry.

I have commented on Steven's comments about alephs below.

It seems to me that this discussion (on having "different" infinities and allowing/storing arithmetic on them) is dead-on-arrival because: - the scope of people who would find this useful is very small - it would change current behaviour - it would be unusual/a first among (popular) programming languages* - consistency is basically impossible: as somebody pointed out, if you have a (Python) function that is 1 / (x ** 2), will the outcome be (1/0)**2 or just 1/0? (1/0)**2 is the consistent outcome, but would require implementing zeros with multiplicity...

This would also create problems underlying, because Python floats (I guess) correspond to the C and CPU floats, so performance and data structure/storage (have to store additional data beyond a C(PU) float to deal with infinities and their size, which would be unbounded if you e.g. allowed exponentials as you would get into things like Cantor Normal Form ( https://en.wikipedia.org/wiki/Ordinal_arithmetic#Cantor_normal_form)).

I honestly think this way lies madness for the floats of a general purpose programming language.

* of course, somebody has got to be first!

On Sun, 18 Oct 2020 at 23:03, Steven D'Aprano steve@pearwood.info wrote:

Oops, I messed up. (Thanks David for pointing that out.)

On Sun, Oct 18, 2020 at 07:45:40PM +1100, Steven D'Aprano wrote:

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

I conflated what I was thinking:

`# note the change in comparison 2**aleph_0 > aleph_0 2**aleph_1 > aleph_1 2**aleph_2 > aleph_2 ...`

which I think is correct regardless of your position on the Continuum Hypothesis (David, care to comment?),

Yes, due to Cantor's diagonal argument: https://en.wikipedia.org/wiki/Cantor%27s_diagonal_argument

with this:

`2**aleph_0 = aleph_1 2**aleph_1 = aleph_2 2**aleph_2 = aleph_3 ...`

which is only true if the Continuum Hypothesis is true

*generalized* Continuum Hypothesis, and in fact it isn't "only true if (G)CH" is much stronger, it is in fact the same statement (if your "..." means "for all ordinals" as GCH (CH is just the first one of those). See https://en.wikipedia.org/wiki/Continuum_hypothesis#The_generalized_continuum... .

Which [Python,] CAS support transfinite and/or surreal numbers and/or other piecewise axioms for an infinity symbol?

Are they vectorizable?

What's wrong with substituting a standard symbol for infinity (instead of prematurely discarding e.g. coefficients/scalars and exponents)?

https://github.com/sympy/sympy/wiki/SymPy-vs.-Sage#functionality https://github.com/sympy/sympy/wiki/SymPy-vs.-Sage#some-syntax-differences sympy.Symbol('Inf') sage. var('Inf')

Should CPython try to be a CAS?

On Mon, Oct 19, 2020, 7:36 AM Henk-Jaap Wagenaar wagenaarhenkjaap@gmail.com wrote:

I have commented on Steven's comments about alephs below.

It seems to me that this discussion (on having "different" infinities and allowing/storing arithmetic on them) is dead-on-arrival because:

- the scope of people who would find this useful is very small
- it would change current behaviour
- it would be unusual/a first among (popular) programming languages*
- consistency is basically impossible: as somebody pointed out, if you
have a (Python) function that is 1 / (x ** 2), will the outcome be (1/0)**2 or just 1/0? (1/0)**2 is the consistent outcome, but would require implementing zeros with multiplicity...

This would also create problems underlying, because Python floats (I guess) correspond to the C and CPU floats, so performance and data structure/storage (have to store additional data beyond a C(PU) float to deal with infinities and their size, which would be unbounded if you e.g. allowed exponentials as you would get into things like Cantor Normal Form ( https://en.wikipedia.org/wiki/Ordinal_arithmetic#Cantor_normal_form)).

I honestly think this way lies madness for the floats of a general purpose programming language.

- of course, somebody has got to be first!
On Sun, 18 Oct 2020 at 23:03, Steven D'Aprano steve@pearwood.info wrote:

Oops, I messed up. (Thanks David for pointing that out.)

On Sun, Oct 18, 2020 at 07:45:40PM +1100, Steven D'Aprano wrote:

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

I conflated what I was thinking:

`# note the change in comparison 2**aleph_0 > aleph_0 2**aleph_1 > aleph_1 2**aleph_2 > aleph_2 ...`

which I think is correct regardless of your position on the Continuum Hypothesis (David, care to comment?),

Yes, due to Cantor's diagonal argument: https://en.wikipedia.org/wiki/Cantor%27s_diagonal_argument

with this:

`2**aleph_0 = aleph_1 2**aleph_1 = aleph_2 2**aleph_2 = aleph_3 ...`

which is only true if the Continuum Hypothesis is true

*generalized* Continuum Hypothesis, and in fact it isn't "only true if (G)CH" is much stronger, it is in fact the same statement (if your "..." means "for all ordinals" as GCH (CH is just the first one of those). See https://en.wikipedia.org/wiki/Continuum_hypothesis#The_generalized_continuum... . _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/Z67R35... Code of Conduct: http://python.org/psf/codeofconduct/

Wes, you seem to just be throwing out a load of questions, to all of which my answer is "I don't know" (and usually "I don't care either").

Do you have an actual proposal here, and if so could you state it clearly and in the form of a description, not a question, please? I'm struggling to find anything useful in your posts at the moment.

Paul

On Mon, 19 Oct 2020 at 13:10, Wes Turner wes.turner@gmail.com wrote:

Which [Python,] CAS support transfinite and/or surreal numbers and/or other piecewise axioms for an infinity symbol?

Are they vectorizable?

What's wrong with substituting a standard symbol for infinity (instead of prematurely discarding e.g. coefficients/scalars and exponents)?

https://github.com/sympy/sympy/wiki/SymPy-vs.-Sage#functionality https://github.com/sympy/sympy/wiki/SymPy-vs.-Sage#some-syntax-differences sympy.Symbol('Inf') sage. var('Inf')

Should CPython try to be a CAS?

On Mon, Oct 19, 2020, 7:36 AM Henk-Jaap Wagenaar wagenaarhenkjaap@gmail.com wrote:

I have commented on Steven's comments about alephs below.

It seems to me that this discussion (on having "different" infinities and allowing/storing arithmetic on them) is dead-on-arrival because:

- the scope of people who would find this useful is very small
- it would change current behaviour
- it would be unusual/a first among (popular) programming languages*
- consistency is basically impossible: as somebody pointed out, if you have a (Python) function that is 1 / (x ** 2), will the outcome be (1/0)**2 or just 1/0? (1/0)**2 is the consistent outcome, but would require implementing zeros with multiplicity...
This would also create problems underlying, because Python floats (I guess) correspond to the C and CPU floats, so performance and data structure/storage (have to store additional data beyond a C(PU) float to deal with infinities and their size, which would be unbounded if you e.g. allowed exponentials as you would get into things like Cantor Normal Form (https://en.wikipedia.org/wiki/Ordinal_arithmetic#Cantor_normal_form)).

I honestly think this way lies madness for the floats of a general purpose programming language.

- of course, somebody has got to be first!
On Sun, 18 Oct 2020 at 23:03, Steven D'Aprano steve@pearwood.info wrote:

Oops, I messed up. (Thanks David for pointing that out.)

On Sun, Oct 18, 2020 at 07:45:40PM +1100, Steven D'Aprano wrote:

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

I conflated what I was thinking:

`# note the change in comparison 2**aleph_0 > aleph_0 2**aleph_1 > aleph_1 2**aleph_2 > aleph_2 ...`

which I think is correct regardless of your position on the Continuum Hypothesis (David, care to comment?),

Yes, due to Cantor's diagonal argument: https://en.wikipedia.org/wiki/Cantor%27s_diagonal_argument

with this:

`2**aleph_0 = aleph_1 2**aleph_1 = aleph_2 2**aleph_2 = aleph_3 ...`

which is only true if the Continuum Hypothesis is true

*generalized* Continuum Hypothesis, and in fact it isn't "only true if (G)CH" is much stronger, it is in fact the same statement (if your "..." means "for all ordinals" as GCH (CH is just the first one of those). See https://en.wikipedia.org/wiki/Continuum_hypothesis#The_generalized_continuum.... _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/Z67R35... Code of Conduct: http://python.org/psf/codeofconduct/

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/76V2IC... Code of Conduct: http://python.org/psf/codeofconduct/

Nope, this time I really have nothing more to say.

On Mon, Oct 19, 2020, 9:22 AM Paul Moore p.f.moore@gmail.com wrote:

Wes, you seem to just be throwing out a load of questions, to all of which my answer is "I don't know" (and usually "I don't care either").

Do you have an actual proposal here, and if so could you state it clearly and in the form of a description, not a question, please? I'm struggling to find anything useful in your posts at the moment.

Paul

On Mon, 19 Oct 2020 at 13:10, Wes Turner wes.turner@gmail.com wrote:

Which [Python,] CAS support transfinite and/or surreal numbers and/or

other piecewise axioms for an infinity symbol?

Are they vectorizable?

What's wrong with substituting a standard symbol for infinity (instead

of prematurely discarding e.g. coefficients/scalars and exponents)?

https://github.com/sympy/sympy/wiki/SymPy-vs.-Sage#functionality

https://github.com/sympy/sympy/wiki/SymPy-vs.-Sage#some-syntax-differences sympy.Symbol('Inf') sage. var('Inf')

Should CPython try to be a CAS?

On Mon, Oct 19, 2020, 7:36 AM Henk-Jaap Wagenaar <

wagenaarhenkjaap@gmail.com> wrote:

I have commented on Steven's comments about alephs below.

It seems to me that this discussion (on having "different" infinities

and allowing/storing arithmetic on them) is dead-on-arrival because:

- the scope of people who would find this useful is very small
- it would change current behaviour
- it would be unusual/a first among (popular) programming languages*
- consistency is basically impossible: as somebody pointed out, if you
have a (Python) function that is 1 / (x ** 2), will the outcome be (1/0)**2 or just 1/0? (1/0)**2 is the consistent outcome, but would require implementing zeros with multiplicity...

This would also create problems underlying, because Python floats (I

guess) correspond to the C and CPU floats, so performance and data structure/storage (have to store additional data beyond a C(PU) float to deal with infinities and their size, which would be unbounded if you e.g. allowed exponentials as you would get into things like Cantor Normal Form ( https://en.wikipedia.org/wiki/Ordinal_arithmetic#Cantor_normal_form)).

I honestly think this way lies madness for the floats of a general

purpose programming language.

- of course, somebody has got to be first!
On Sun, 18 Oct 2020 at 23:03, Steven D'Aprano steve@pearwood.info

wrote:

Oops, I messed up. (Thanks David for pointing that out.)

On Sun, Oct 18, 2020 at 07:45:40PM +1100, Steven D'Aprano wrote:

Each of these number systems have related, but slightly different, rules. For example, IEEE-754 has a single signed infinity and 2**INF

is

exactly equal to INF. But in transfinite arithmetic, 2**INF is

strictly

greater than INF (for every infinity):

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

I conflated what I was thinking:

`# note the change in comparison 2**aleph_0 > aleph_0 2**aleph_1 > aleph_1 2**aleph_2 > aleph_2 ...`

Yes, due to Cantor's diagonal argument:

https://en.wikipedia.org/wiki/Cantor%27s_diagonal_argument

with this:

`2**aleph_0 = aleph_1 2**aleph_1 = aleph_2 2**aleph_2 = aleph_3 ...`

which is only true if the Continuum Hypothesis is true

*generalized* Continuum Hypothesis, and in fact it isn't "only true if

(G)CH" is much stronger, it is in fact the same statement (if your "..." means "for all ordinals" as GCH (CH is just the first one of those). See https://en.wikipedia.org/wiki/Continuum_hypothesis#The_generalized_continuum... .

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at

https://mail.python.org/archives/list/python-ideas@python.org/message/Z67R35...

Code of Conduct: http://python.org/psf/codeofconduct/

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at

https://mail.python.org/archives/list/python-ideas@python.org/message/76V2IC...

Code of Conduct: http://python.org/psf/codeofconduct/

On Sun, Oct 18, 2020, 6:04 PM Steven D'Aprano steve@pearwood.info wrote:

Oops, I messed up. (Thanks David for pointing that out.)

Yup. The below is all entirely correct. Still, as fun as transfinite set theory is, these bits of it aren't actually relevant to Python and IEEE-754.

It's enough just to note that transfinite numbers are a lot different than real numbers. Just because floats, as concrete numeric type, notionally contain two transfinites, those special numbers won't follow a lot of the rules other floats do. There are good theoretical reasons, but one just has to start by accepting that.

And no, absolutely no one is suggesting adding actual Cantorian transfinite arithmetic to Python. Of course someone could write (and has written) libraries to do interesting math of this sort, but that's way outside the core language.

On Sun, Oct 18, 2020 at 07:45:40PM +1100, Steven D'Aprano wrote:

`2**aleph_0 < aleph_1 2**aleph_1 < aleph_2 2**aleph_2 < aleph_3`

I conflated what I was thinking:

`# note the change in comparison 2**aleph_0 > aleph_0 2**aleph_1 > aleph_1 2**aleph_2 > aleph_2 ...`

which I think is correct regardless of your position on the Continuum Hypothesis (David, care to comment?), with this:

`2**aleph_0 = aleph_1 2**aleph_1 = aleph_2 2**aleph_2 = aleph_3 ...`

which is only true if the Continuum Hypothesis is true, and then wrote down something which was complete nonsense. Sorry.

-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/AENOEZ... Code of Conduct: http://python.org/psf/codeofconduct/

Correction to previous post:

On 11/10/2020 22:47, Wes Turner wrote:

`assert inf / inf == 1`

I should have said:

That should raise an exception; inf/inf is meaningless (just as 0/0 is meaningless).

Best wishes Rob Cliffe

No, 2 times something is greater than something. Something over something is 1.

If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.

assert 1 / 0 != 2 / 0 assert 2*inf > inf assert inf / inf == 1

I should have said capricious (not specious). I'm again replying to the main thread because this is relevant: there would need to be changes to tests in order to return (scalar times) infinity instead of ZeroDivisionError.

We should not discard the scalar in scalar*infinity expressions.

On Sun, Oct 11, 2020, 5:18 PM Chris Angelico rosuav@gmail.com wrote:

On Mon, Oct 12, 2020 at 8:07 AM Wes Turner wes.turner@gmail.com wrote:

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

On what basis? If you start by assuming that infinity is a number, then sure, you're going to deduce that double it must be a greater number. But you're just concluding your own assumption, not proving anything.

And:

`inf / inf = 1`

Is that the case?

from math import inf inf / inf

nan

# When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2

# If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1

# I think it's specious to argue that there are infinity solutions;

that axioms of symbolic mathematics do not apply because infinity

Once again, you start by assuming that infinity is a number, and that you can divide by it (which is what happens when you "solve for x" by removing the infinities). You can't prove something by first assuming it.

"Infinity" isn't a number. In the IEEE 754 system, it is a value, but it's still not a number (although it's distinct from Not A Number, just to confuse everyone). In mathematics, it's definitely not an actual number or value.

ChrisA ______________________________

On Sun, Oct 11, 2020 at 5:04 PM Wes Turner wes.turner@gmail.com wrote:

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

And:

`inf / inf = 1 # When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2 # If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1 # I think it's specious to argue that there are infinity solutions; that axioms of symbolic mathematics do not apply because infinity`

This is relevant to the (now-forked) main thread if the plan is to return inf/-inf/+inf instead of raising ZeroDivisionError; so I'm replying to the main thread.

On Sun, Oct 11, 2020, 4:10 PM Chris Angelico rosuav@gmail.com wrote: On Mon, Oct 12, 2020 at 5:06 AM Wes Turner wes.turner@gmail.com wrote:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity,

NegativeInfinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

If you try to treat "infinity" as an actual number, you're inevitably going to run into paradoxes. Consider instead: 1/x tends towards +∞ as x tends towards 0 (if x starts out positive), therefore we consider that 1/0 is +∞. By that logic, the limit of 2/0 is the exact same thing. It's still not a perfect system, and division by zero is always going to cause problems, but it's far less paradoxical if you don't try to treat 2/0 as different from 1/0 :)

BTW, you're technically correct, in that 2/0 would be the same as 2 * (whatever 1/0 is), but that's because 2*x tends towards +∞ as x tends towards +∞, meaning that 2*∞ is also ∞.

ChrisA

On Sun, Oct 11, 2020 at 2:03 PM Wes Turner wes.turner@gmail.com wrote:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity, NegativeInfinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

A proper CAS really is advisable. FWIU, different CAS have different outputs for the above problem (most just disregard the scalar because it's infinity so who care if that cancels out later).

Where are the existing test cases for arithemetic calculations with (scalar times) IEEE-754 int, +inf, or -inf as the output?

On Tue, Sep 15, 2020 at 1:54 AM David Mertz mertz@gnosis.cx wrote:

Likewise, a bunch of operations really should be NaN that are exceptions now.

On Mon, Sep 14, 2020, 5:26 PM Ben Rudiak-Gould benrudiak@gmail.com wrote:

On Mon, Sep 14, 2020 at 9:36 AM Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Christopher Barker writes:

IEEE 754 is a very practical standard -- it was well designed, and

is

widely used and successful. It is not perfect, and in certain use

cases, it

may not be the best choice. But it's a really good idea to keep to

that

standard by default.

I feel the same way; I really wish Python was better about following IEEE 754.

I agree, but Python doesn't. It raises on some infs (generally

speaking, true infinities), and returns inf on others (generally speaking, overflows).

It seems to be very inconsistent. From testing just now:

math.lgamma(0) raises "ValueError: math domain error"

math.exp(1000) raises "OverflowError: math range error"

math.e ** 1000 raises "OverflowError: (34, 'Result too large')"

(math.e ** 500) * (math.e ** 500) returns inf

sum([1e308, 1e308]) returns inf

math.fsum([1e308, 1e308]) raises "OverflowError: intermediate

overflow in fsum"

math.fsum([1e308, inf, 1e308]) returns inf

math.fsum([inf, 1e308, 1e308]) raises "OverflowError: intermediate

overflow in fsum"

float('1e999') returns inf

float.fromhex('1p1024') raises "OverflowError: hexadecimal value too

large to represent as a float"

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/GLUX5W... Code of Conduct: http://python.org/psf/codeofconduct/

On Mon, Oct 12, 2020 at 8:42 AM Wes Turner wes.turner@gmail.com wrote:

No, 2 times something is greater than something. Something over something is 1.

If we change the division axiom to be piecewise with an exception only for infinity, we could claim that any problem involving division of a symbol is unsolvable because the symbol could be infinity.

Again, you start with the assumption that infinity is a number. "2 times something is greater than something" applies only to positive real numbers - not to zero, not to negative numbers, not to complex numbers.

This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infinity, then they are equal.

assert 1 / 0 != 2 / 0 assert 2*inf > inf assert inf / inf == 1

Where do these assertions hold true? Certainly not in Python, nor in mathematical real numbers.

I should have said capricious (not specious). I'm again replying to the main thread because this is relevant: there would need to be changes to tests in order to return (scalar times) infinity instead of ZeroDivisionError.

We should not discard the scalar in scalar*infinity expressions.

The scalar becomes irrelevant when infinity is a limit, rather than a number.

Further discussion probably belongs on python-list rather than here.

ChrisA

Can you explain why Python should behave differently than other languages?

Python:

math.inf == 2 * math.inf

True

JavaScript:

Infinity == 2 * Infinity

true

Wolfram Alpha: https://www.wolframalpha.com/input/?i=inf+%3D+2+*+inf+%3D+3+*+inf ∞ = 2∞ = 3∞ True

On Sun, 2020-10-11 at 17:39 -0400, Wes Turner wrote: No, 2 times something is greater than something. Something over somethi

ng is 1. If we change the division axiom to be piecewise with an exception only

for infinity, we could claim that any problem involving division of a s

ymbol is unsolvable because the symbol could be infinity. This is incorrect: x / 2 is unsolvable because x could be infinity x / 2 > x / 3 (where x > 0; Z+) is indeterminate because if x is infini

ty, then they are equal.

assert 1 / 0 != 2 / 0

assert 2*inf > inf assert inf / inf == 1

I should have said capricious (not specious). I'm again replying to the

main thread because this is relevant: there would need to be changes t

o tests in order to return (scalar times) infinity instead of ZeroDivis

ionError.

We should not discard the scalar in scalar*infinity expressions.

On Sun, Oct 11, 2020, 5:18 PM Chris Angelico rosuav@gmail.com wrote:

On Mon, Oct 12, 2020 at 8:07 AM Wes Turner wes.turner@gmail.com wro

te:

So you're arguing that the scalar is irrelevant? That `2*inf == inf`?

I disagree because: ```2*inf > inf```

On what basis? If you start by assuming that infinity is a number, then sure, you're going to deduce that double it must be a greater number. But you're just concluding your own assumption, not proving anything.

And:

`inf / inf = 1`

Is that the case?

from math import inf inf / inf

nan

# When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2

# If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1

# I think it's specious to argue that there are infinity solutions

; that axioms of symbolic mathematics do not apply because infinity

Once again, you start by assuming that infinity is a number, and that

you can divide by it (which is what happens when you "solve for x" by

removing the infinities). You can't prove something by first assuming

it.

"Infinity" isn't a number. In the IEEE 754 system, it is a value, but

it's still not a number (although it's distinct from Not A Number, just to confuse everyone). In mathematics, it's definitely not an actual number or value.

ChrisA ______________________________

On Sun, Oct 11, 2020 at 5:04 PM Wes Turner wes.turner@gmail.com wrote

:

So you're arguing that the scalar is irrelevant?That `2*inf == inf`?

I disagree because: ```2*inf > inf``` And:

`inf / inf = 1 # When we solve for symbol x: 2*inf*x = inf 2*x = 1 x = 1/2 # If we discard the scalar instead: 2*inf*x = inf inf*x = inf x = 1 # I think it's specious to argue that there are infinity solutions;`

that axioms of symbolic mathematics do not apply because infinity

`This is relevant to the (now- forked) main thread if the plan is to return inf/- inf/+inf instead of raising ZeroDivisionError; so I'm replying to the`

main thread.

On Sun, Oct 11, 2020, 4:10 PM Chris Angelico rosuav@gmail.com wrote

: On Mon, Oct 12, 2020 at 5:06 AM Wes Turner wes.turner@gmail.com wro

te:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity, Negative

Infinity, ComplexInfinity.

Regarding a symbolic result for 1/0:

If you try to treat "infinity" as an actual number, you're inevitably

going to run into paradoxes. Consider instead: 1/x tends towards +∞ a

s x tends towards 0 (if x starts out positive), therefore we consider that 1/0 is +∞. By that logic, the limit of 2/0 is the exact same thing. It's still not a perfect system, and division by zero is alway

s going to cause problems, but it's far less paradoxical if you don't try to treat 2/0 as different from 1/0 :)

BTW, you're technically correct, in that 2/0 would be the same as 2 *

(whatever 1/0 is), but that's because 2*x tends towards +∞ as x tends

towards +∞, meaning that 2*∞ is also ∞.

ChrisA

On Sun, Oct 11, 2020 at 2:03 PM Wes Turner wes.turner@gmail.com wro

te:

SymPy ComplexInfinity, 1/0 < 2/0, *tests* for symbolic results

FWIW, SymPy (a CAS: Computer Algebra System) has Infinity, Negative

Infinity, ComplexInfinity. Regarding a symbolic result for 1/0:

A proper CAS really is advisable. FWIU, different CAS have differen

t outputs for the above problem (most just disregard the scalar bec

ause it's infinity so who care if that cancels out later).

Where are the existing test cases for arithemetic calculations with

(scalar times) IEEE-754 int, +inf, or -inf as the output?

On Tue, Sep 15, 2020 at 1:54 AM David Mertz mertz@gnosis.cx wrote

:

Thanks so much Ben for documenting all these examples. I've been

frustrated by the inconsistencies, but hasn't realized all of tho

se you note.

It would be a breaking change, but I'd really vastly prefer if al

most all of those OverflowErrors and others were simply infinitie

s. That's much closer to the spirit of IEEE-754.

The tricky case is 1./0. Division is such an ordinary operation,

and it's so easy to get zero in a variable accidentally. That one

still feels like an exception, but yes 1/1e-323 vs. 1/1e- 324 would them remain a sore spot.

Likewise, a bunch of operations really should be NaN that are exc

eptions now.

On Mon, Sep 14, 2020, 5:26 PM Ben Rudiak- Gould benrudiak@gmail.com wrote:

On Mon, Sep 14, 2020 at 9:36 AM Stephen J. Turnbull <turnbull. stephen.fw@u.tsukuba.ac.jp> wrote:

Christopher Barker writes: > IEEE 754 is a very practical standard -- it was well designed, and is > widely used and successful. It is not perfect, and in cert

ain use cases, it > may not be the best choice. But it's a really good idea to

keep to that > standard by default.

I feel the same way; I really wish Python was better about foll

owing IEEE 754.

I agree, but Python doesn't. It raises on some infs (general

ly speaking, true infinities), and returns inf on others (genera

lly speaking, overflows).

It seems to be very inconsistent. From testing just now:

math.lgamma(0) raises "ValueError: math domain error"

math.exp(1000) raises "OverflowError: math range error"

math.e ** 1000 raises "OverflowError: (34, 'Result too large'

)"

(math.e ** 500) * (math.e ** 500) returns inf

sum([1e308, 1e308]) returns inf

math.fsum([1e308, 1e308]) raises "OverflowError: intermediate

overflow in fsum"

math.fsum([1e308, inf, 1e308]) returns inf

math.fsum([inf, 1e308, 1e308]) raises "OverflowError: interme

diate overflow in fsum"

float('1e999') returns inf

float.fromhex('1p1024') raises "OverflowError: hexadecimal va

lue too large to represent as a float"

I get the impression that little planning has gone into this. T

here's no consistency in the OverflowError messages. 1./0. rais

es ZeroDivisionError which isn't a subclass of OverflowError. l

gamma(0) raises a ValueError, which isn't even a subclass of Ar

ithmeticError. The function has a pole at 0 with a well- defined two- sided limit of +inf. If it isn't going to return +inf then it o

ught to raise ZeroDivisionError, which should obviously be a su

bclass of OverflowError.

Because of the inconsistent handling of overflow, many function

s aren't even monotonic. exp(2*x) returns a float for x <= 709.

782712893384, raises OverflowError for 709.782712893384 < x <=

8.98846567431158e+307, and returns a float for x > 8.9884656743

1158e+307.

1./0. is not a true infinity. It's the reciprocal of a number t

hat may have underflowed to zero. It's totally inconsistent to

return inf for 1/1e-323 and raise an exception for 1/1e- 324, as Python does.

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/pyth on-ideas@python.org/message/TXEZTNVIKJFEGPH535KYZ4B5KVNNGBZZ/ Code of Conduct: http://python.org/psf/codeofconduct/

Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python -ideas@python.org/message/GLUX5WVRF3VBJTD3EBH5MCSRWBASJZOZ/ Code of Conduct: http://python.org/psf/codeofconduct/

_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas @python.org/message/WFPPQ2R4Q74IW3XME5Q4LARXZRDYHKXL/ Code of Conduct: http://python.org/psf/codeofconduct/

On 12/10/20 10:39 am, Wes Turner wrote:

We should not discard the scalar in scalar*infinity expressions.

I don't think that would help as much as you seem to imagine it would.

Consider f(x) = 1/x**2, g(x) = 1/x**3, h(x) = f(x) / g(x).

Keeping a scalar multiplier attached to infinities isn't going to help you get a sensible result for h(0) given f(0) and g(0).

Doing that kind of thing would require a full-blown computer algebra system capable of reasoning about limits.

On Tue, 15 Sep 2020 at 08:12, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Ben Rudiak-Gould writes:

1./0. is not a true infinity.

Granted, I was imprecise. To be precise, 1.0 / 0.0 *could* be a true infinity, and in some cases (1.0 / float(0)) *provably* is, while 1e1000 *provably* is not a true infinity.

I think we're getting to a point where the argument is getting way too theoretical to make sense any more. I'm genuinely not clear from the fragment quoted here,

1. What a "true infinity" is. Are we talking solely about IEEE-754? Because mathematically, different disciplines have different views, and many of them don't even include infinity in the set of numbers. 2. What do 1.0 and 0.0 mean? The literals in Python translate to specific bit patterns, so we can apply IEEE-754 rules to those bit patterns. There's nothing to discuss here, just the application of a particular set of rules. (Unless we're discussing which set of rules to apply, but I thought IEEE-754 was assumed). So Ben's statement seems to imply he's not talking just about IEEE-754 bit patterns. 3. Can you give an example of 1.0/0.0 *not* being a "true infinity"? I have a feeling you're going to point to denormalised numbers close to zero, but why are you expressing them as "0.0"? 4. Can you provide the proofs you claim exist? I'm not actually that interested in the proofs themselves, I'm just trying to determine what your axioms and underlying model are.

(Note: this has drifted a long way from anything that has real relevance to Python - arguments this theoretical will almost certainly fall foul of "practicality beats purity" when we get to arguing what the language should do. I'm just curious to see how the theoretical debate pans out).

Paul

Paul Moore writes:

On Tue, 15 Sep 2020 at 08:12, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Ben Rudiak-Gould writes:

1./0. is not a true infinity.

Granted, I was imprecise. To be precise, 1.0 / 0.0 *could* be a true infinity, and in some cases (1.0 / float(0)) *provably* is, while 1e1000 *provably* is not a true infinity.

I think we're getting to a point where the argument is getting way too theoretical to make sense any more. I'm genuinely not clear from the fragment quoted here,

- What a "true infinity" is. Are we talking solely about IEEE-754?

Not solely. We're talking about mathematical infinities, such as the count of all integers or the length of the real line, and how they are modeled in IEEE-754 and Python.

Because mathematically, different disciplines have different views, and many of them don't even include infinity in the set of numbers.

But in IEEE-754, inf behaves like the positive infinity of the extended real number line: inf + inf = inf, x > 0 => inf * x = inf, inf - inf = nan, and so on. We need to be talking about a mathematics that at least has defined the extended reals.

- What do 1.0 and 0.0 mean? The literals in Python translate to
specific bit patterns, so we can apply IEEE-754 rules to those bit patterns. There's nothing to discuss here, just the application of a particular set of rules.

Except that application is not consistent. That was the point of Ben's post.

(Unless we're discussing which set of rules to apply, but I thought IEEE-754 was assumed). So Ben's statement seems to imply he's not talking just about IEEE-754 bit patterns.

He's talking about the arithmetic of floating point numbers, which involves rounding rules intended to model the extended real line.

- Can you give an example of 1.0/0.0 *not* being a "true infinity"? I
have a feeling you're going to point to denormalised numbers close to zero, but why are you expressing them as "0.0"?

Not subnormal numbers, but non-zero numbers that round to zero.

1e200

1e200

1e-200

1e-200

1e200 == 1.0 / 1e-200

True

1e-200 * 1e-200 == 0.0

True

1.0 / (1e-200 * 1e-200)

Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: float division by zero

1e200 * 1e200

inf

- Can you provide the proofs you claim exist?

Proofs of what? All of this is just straightforward calculations in the extended real line, on the one hand, in IEEE 754 floats on the other hand, and in Python, on the gripping hand.[1]

For numbers with magnitudes "near" 1 (ie, less than about 100 orders of magnitude bigger or smaller), the three arithmetics agree tolerably well for practical purposes (and Python and IEEE 754 agree exactly). If you need trignometric or exponential functions, things get quite a bit more restricted -- things break down at pi/2.

For numbers with magnitudes "near" infinity, or nearly infinitesimal, things break down in Python. Whether you consider that breakdown to be problematic or not depends on how you view the (long) list of Curious Things The Dog Did (Not Do) In The Night in Ben's post. I think they're pretty disastrous. I'd be much happier with *either* consistently raising on non-representable finite results, or consistently returning -inf, 0.0, inf, or nan. That's not the Python we have.

(Note: this has drifted a long way from anything that has real relevance to Python - arguments this theoretical will almost certainly fall foul of "practicality beats purity" when we get to arguing what the language should do. I'm just curious to see how the theoretical debate pans out).

I disagree. This is entirely on the practical side of things!

Calculations on the extended real line are "just calculations", as are calculations with IEEE 754 floats. Any attentive high school student can learn to do them (at least with the help of a computer for correct rounding in the case of IEEE 754 floats :-). There's no theory to discuss (except for terminology like "true infinity").

The question of whether Python diverges from IEEE 754 (which turns on whether IEEE 754 recommends that you raise exceptions or return inf/nan but not both), and the question of whether the IEEE 754 model of "overflow as infinity" is intuitive/useful to users of Python who *don't* use NumPy, are the questions under discussion here.

Now, to be fair, there is a practicality beats purity argument. It can be argued (I think Ben or maybe Chris A alluded to this) that "overflows usually' just happen but division by zero usually' is a logic error". Therefore returning inf in the case of overflow (and continuing the computation), and raising on zero division (stopping the computation and getting the attention of the user), is the pragmatic sweet spot. I disagree, but it's a viable argument.

Footnotes: [1] If you haven't read The Mote in God's Eye, that's the third hand of the aliens, which is big, powerful, clumsy, and potentially deadly. Pretty much the way I think of "inf"!

On Tue, 15 Sep 2020 at 10:29, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Paul Moore writes:

On Tue, 15 Sep 2020 at 08:12, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Ben Rudiak-Gould writes:

1./0. is not a true infinity.

Granted, I was imprecise. To be precise, 1.0 / 0.0 *could* be a true infinity, and in some cases (1.0 / float(0)) *provably* is, while 1e1000 *provably* is not a true infinity.

I think we're getting to a point where the argument is getting way too theoretical to make sense any more. I'm genuinely not clear from the fragment quoted here,

- What a "true infinity" is. Are we talking solely about IEEE-754?
Not solely. We're talking about mathematical infinities, such as the count of all integers or the length of the real line, and how they are modeled in IEEE-754 and Python.

OK, so to me, 1.0 / 0.0 *is* a "true infinity" in that sense. If you divide "one" by "zero" the only plausible interpretation - if you allow infinity in your number system - is that you get infinity as a result. Of course that just pushes the question back to whether you mean (mathematical) "one" and "zero" when you make that statement.

I get that Ben is actually saying "things that round to 1" and "things that round to 0", but at that point error propagation and similar details come into play, making even equality a somewhat vague concept.

Because mathematically, different disciplines have different views, and many of them don't even include infinity in the set of numbers.

But in IEEE-754, inf behaves like the positive infinity of the extended real number line: inf + inf = inf, x > 0 => inf * x = inf, inf - inf = nan, and so on. We need to be talking about a mathematics that at least has defined the extended reals.

OK.

- What do 1.0 and 0.0 mean? The literals in Python translate to
specific bit patterns, so we can apply IEEE-754 rules to those bit patterns. There's nothing to discuss here, just the application of a particular set of rules.

Except that application is not consistent. That was the point of Ben's post.

(Unless we're discussing which set of rules to apply, but I thought IEEE-754 was assumed). So Ben's statement seems to imply he's not talking just about IEEE-754 bit patterns.

He's talking about the arithmetic of floating point numbers, which involves rounding rules intended to model the extended real line.

Again OK, but in the face of rounding rules, many "obvious" mathematical properties, such as associativity and distributivity, don't hold. So we have to be *very* careful when inferring equivalences like the one you use below, a * b = c => 1.0 / (a * b) = 1.0 / c.

Note that I'm not saying here that Python's behaviour might not be inconsistent, but rather that it's not obvious (to me, at least) that there is an intuitively consistent set of rules - so Python has chosen one particular way of being inconsistent, and the question is more about whether we like an alternative form of inconsistency better than about "should Python be consistent". If a consistent set of rules *is* possible then "we should be consistent" is a purity argument that may or may not stand against practical considerations like "raising an exception is more user friendly for people who don't understand IEEE-754".

- Can you give an example of 1.0/0.0 *not* being a "true infinity"? I
have a feeling you're going to point to denormalised numbers close to zero, but why are you expressing them as "0.0"?

Not subnormal numbers, but non-zero numbers that round to zero.

1e200

1e200

1e-200

1e-200

1e200 == 1.0 / 1e-200

True

1e-200 * 1e-200 == 0.0

True

1.0 / (1e-200 * 1e-200)

Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: float division by zero

1e200 * 1e200

inf

See above.

- Can you provide the proofs you claim exist?
Proofs of what? All of this is just straightforward calculations in the extended real line, on the one hand, in IEEE 754 floats on the other hand, and in Python, on the gripping hand.[1]

You claimed that "1e1000 *provably* is not a true infinity". How would you prove that?

Typing it into Python gives

1e1000

inf

That's a proof that in Python, 1e1000 *is* a true infinity. On the extended real line, 1e1000 is not a true infinity because they are different points on the line. In IEEE 754 I'd have to check the details, but I think someone posted that the standard defines parsing rules such that 1e1000 must translate to infinity.

So when I asked for your proof, I was trying to determine which set of rules you were using.

For numbers with magnitudes "near" 1 (ie, less than about 100 orders of magnitude bigger or smaller), the three arithmetics agree tolerably well for practical purposes (and Python and IEEE 754 agree exactly). If you need trignometric or exponential functions, things get quite a bit more restricted -- things break down at pi/2.

For numbers with magnitudes "near" infinity, or nearly infinitesimal, things break down in Python. Whether you consider that breakdown to be problematic or not depends on how you view the (long) list of Curious Things The Dog Did (Not Do) In The Night in Ben's post.

Precisely. There are three models here, Python's, IEEE-754's and the extended real line. All have different rules. Python's rules have been established organically over time, possibly based on judgement calls about what is "useful behaviour", possibly by accident.

I think they're pretty disastrous. I'd be much happier with *either* consistently raising on non-representable finite results, or consistently returning -inf, 0.0, inf, or nan. That's not the Python we have.

I think we could have rules that are easier to reason with, but I doubt anyone but specialists are ever likely to care much. Specialists are an important group of users, so I'm not dismissing the issue, but specialists are unlikely to be the people who want inf to be a builtin rather than a name in the math module, so what specialists prefer isn't particularly relevant to the *original* request in this thread.

Having said that, do I care about making better rules for how Python works? Well, sort of. I don't do higher maths in Python that often - most of my work is basically finite. I use floating point mostly for probability calculations and plotting.

What's bothering me here is that Ben's main list is all related to OverflowError and ValueError exceptions, and I'm fine with debating the details of those. I personally don't care much, and it should be a different thread than the "add inf to builtins" proposal, but if the specialists want something different, that's fine with me. But then things spilled over to 1.0 / 0.0, and there I *do* care. Division is a fundamental operation, divide by zero is nearly always an error in non-specialist code, and non-specialists really don't want to see infinities cropping up in their calculations.

So by all means discuss math.lgamma. But be very careful translating any intuitions you have over that across to division.

Here's a question.

1.0 / 2.0 is 0.5. No question there. 1 / 2 is *also* 0.5. So integer division can give float values. And should give "the same result" (mathematically). 1.0 / 0.0 is being debated, but let's say we agree that it should produce inf, because that's IEEE-754. Now, what about 1 / 0? Do we violate the principle that led to 1 / 2 being 0.5? Or do we allow this to generate a floating infinity? 1 // 0 has to give ZeroDivisionError, as there's no possible *integer* result. But now I find myself uncomfortable that 1//0 raises an exception but 1/0 doesn't.

And as soon as we start considering integer division, we're talking about breaking a *vast* amount of code.

As I said above, pick your preferred form of inconsistency. But don't expect to get perfect consistency, it's not an option.

(Note: this has drifted a long way from anything that has real relevance to Python - arguments this theoretical will almost certainly fall foul of "practicality beats purity" when we get to arguing what the language should do. I'm just curious to see how the theoretical debate pans out).

I disagree. This is entirely on the practical side of things!

Calculations on the extended real line are "just calculations", as are calculations with IEEE 754 floats. Any attentive high school student can learn to do them (at least with the help of a computer for correct rounding in the case of IEEE 754 floats :-). There's no theory to discuss (except for terminology like "true infinity").

But extended reals are only one thing you might be trying to model with Python's floating point. Non-specialists are more likely to have an (imperfect) mental model of a calculator. Which typically errors on divide by zero.

The question of whether Python diverges from IEEE 754 (which turns on whether IEEE 754 recommends that you raise exceptions or return inf/nan but not both), and the question of whether the IEEE 754 model of "overflow as infinity" is intuitive/useful to users of Python who *don't* use NumPy, are the questions under discussion here.

Python floats exist in a context where they need to interact "consistently" with other types. So there's a tension between precisely modeling IEEE-754 and fitting with the rest of the language. In general, I'm in favour of floats accurately following IEEE-754, but we need to be careful not to be too dogmatic at the edge cases.

Also, we need to remember that IEEE-754 might define rules for how division works, but it doesn't (can't) mandate how Python spells that operation, so in theory, we could have math.iee743_div for "a strictly conforming" version. And once we start thinking about that it becomes clear that "which set of rules gets to be called /" is a matter of user friendliness as much as "correctness".

Now, to be fair, there is a practicality beats purity argument. It can be argued (I think Ben or maybe Chris A alluded to this) that "overflows usually' just happen but division by zero usually' is a logic error". Therefore returning inf in the case of overflow (and continuing the computation), and raising on zero division (stopping the computation and getting the attention of the user), is the pragmatic sweet spot. I disagree, but it's a viable argument.

That's probably my main point, coupled with the points that "division, as a language built in operator, is very different from functions in the math module", and "division is polymorphic, and consistent behaviour across types is an extra consideration that math functions don't need to be concerned about".

Footnotes: [1] If you haven't read The Mote in God's Eye, that's the third hand of the aliens, which is big, powerful, clumsy, and potentially deadly. Pretty much the way I think of "inf"!

Yep, spot on!

Paul

To sum up these discussions, I think it should be said that perhaps a look should be taken at the structure of math-based errors and exceptions, but this discussion should be moved to a new thread on the mailing list perhaps. (I agree that the exceptions make little sense, and I have noticed this)

I'd just like to add that under many circumstances, division by 0 makes perfect sense. For example, in the Riemann Sphere ( https://en.wikipedia.org/wiki/Riemann_sphere), 1/0 == infinity (of course, this is not a signed infinity, but rather a single infinity, sometimes called 'complex infinity')

And, under complete euclidean division, it makes sense to describe `x // 0 == 0` and `x % 0 == x`, so that:

(a, b) := (x // y, x % y) implies x = a * y + b

However, should Python cater to these use cases? I don't think so, because most users are committing some sort of error when they divide by zero, and Python should make them acknowledge that explicitly.

Most users aren't abstract theorists. Python shouldn't assume they are

Additionally, not raising an exception on division by float zero would mean the following operations behave vastly differently:

1 / 0

<raises error>

1 / 0.0

inf

This would also be very unexpected

---- *Cade Brown* Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.com ICL/College Email: cade@utk.edu

On Tue, Sep 15, 2020 at 7:02 AM Paul Moore p.f.moore@gmail.com wrote:

On Tue, 15 Sep 2020 at 10:29, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Paul Moore writes:

On Tue, 15 Sep 2020 at 08:12, Stephen J. Turnbull turnbull.stephen.fw@u.tsukuba.ac.jp wrote:

Ben Rudiak-Gould writes:

1./0. is not a true infinity.

Granted, I was imprecise. To be precise, 1.0 / 0.0 *could* be a

true

infinity, and in some cases (1.0 / float(0)) *provably* is, while 1e1000 *provably* is not a true infinity.

- What a "true infinity" is. Are we talking solely about IEEE-754?
Not solely. We're talking about mathematical infinities, such as the count of all integers or the length of the real line, and how they are modeled in IEEE-754 and Python.

OK, so to me, 1.0 / 0.0 *is* a "true infinity" in that sense. If you divide "one" by "zero" the only plausible interpretation - if you allow infinity in your number system - is that you get infinity as a result. Of course that just pushes the question back to whether you mean (mathematical) "one" and "zero" when you make that statement.

I get that Ben is actually saying "things that round to 1" and "things that round to 0", but at that point error propagation and similar details come into play, making even equality a somewhat vague concept.

Because mathematically, different disciplines have different views, and many of them don't even include infinity in the set of numbers.

But in IEEE-754, inf behaves like the positive infinity of the extended real number line: inf + inf = inf, x > 0 => inf * x = inf, inf - inf = nan, and so on. We need to be talking about a mathematics that at least has defined the extended reals.

OK.

- What do 1.0 and 0.0 mean? The literals in Python translate to
specific bit patterns, so we can apply IEEE-754 rules to those bit patterns. There's nothing to discuss here, just the application of a particular set of rules.

Except that application is not consistent. That was the point of Ben's post.

(Unless we're discussing which set of rules to apply, but I thought IEEE-754 was assumed). So Ben's statement seems to imply he's not talking just about IEEE-754 bit patterns.

He's talking about the arithmetic of floating point numbers, which involves rounding rules intended to model the extended real line.

Again OK, but in the face of rounding rules, many "obvious" mathematical properties, such as associativity and distributivity, don't hold. So we have to be *very* careful when inferring equivalences like the one you use below, a * b = c => 1.0 / (a * b) = 1.0 / c.

Note that I'm not saying here that Python's behaviour might not be inconsistent, but rather that it's not obvious (to me, at least) that there is an intuitively consistent set of rules - so Python has chosen one particular way of being inconsistent, and the question is more about whether we like an alternative form of inconsistency better than about "should Python be consistent". If a consistent set of rules *is* possible then "we should be consistent" is a purity argument that may or may not stand against practical considerations like "raising an exception is more user friendly for people who don't understand IEEE-754".

- Can you give an example of 1.0/0.0 *not* being a "true infinity"? I
have a feeling you're going to point to denormalised numbers close to zero, but why are you expressing them as "0.0"?

Not subnormal numbers, but non-zero numbers that round to zero.

1e200

1e200

1e-200

1e-200

1e200 == 1.0 / 1e-200

True

1e-200 * 1e-200 == 0.0

True

1.0 / (1e-200 * 1e-200)

Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: float division by zero

1e200 * 1e200

inf

See above.

- Can you provide the proofs you claim exist?
Proofs of what? All of this is just straightforward calculations in the extended real line, on the one hand, in IEEE 754 floats on the other hand, and in Python, on the gripping hand.[1]

You claimed that "1e1000 *provably* is not a true infinity". How would you prove that?

Typing it into Python gives

1e1000

inf

That's a proof that in Python, 1e1000 *is* a true infinity. On the extended real line, 1e1000 is not a true infinity because they are different points on the line. In IEEE 754 I'd have to check the details, but I think someone posted that the standard defines parsing rules such that 1e1000 must translate to infinity.

So when I asked for your proof, I was trying to determine which set of rules you were using.

For numbers with magnitudes "near" 1 (ie, less than about 100 orders of magnitude bigger or smaller), the three arithmetics agree tolerably well for practical purposes (and Python and IEEE 754 agree exactly). If you need trignometric or exponential functions, things get quite a bit more restricted -- things break down at pi/2.

For numbers with magnitudes "near" infinity, or nearly infinitesimal, things break down in Python. Whether you consider that breakdown to be problematic or not depends on how you view the (long) list of Curious Things The Dog Did (Not Do) In The Night in Ben's post.

Precisely. There are three models here, Python's, IEEE-754's and the extended real line. All have different rules. Python's rules have been established organically over time, possibly based on judgement calls about what is "useful behaviour", possibly by accident.

I think they're pretty disastrous. I'd be much happier with *either* consistently raising on non-representable finite results, or consistently returning -inf, 0.0, inf, or nan. That's not the Python we have.

I think we could have rules that are easier to reason with, but I doubt anyone but specialists are ever likely to care much. Specialists are an important group of users, so I'm not dismissing the issue, but specialists are unlikely to be the people who want inf to be a builtin rather than a name in the math module, so what specialists prefer isn't particularly relevant to the *original* request in this thread.

Having said that, do I care about making better rules for how Python works? Well, sort of. I don't do higher maths in Python that often - most of my work is basically finite. I use floating point mostly for probability calculations and plotting.

What's bothering me here is that Ben's main list is all related to OverflowError and ValueError exceptions, and I'm fine with debating the details of those. I personally don't care much, and it should be a different thread than the "add inf to builtins" proposal, but if the specialists want something different, that's fine with me. But then things spilled over to 1.0 / 0.0, and there I *do* care. Division is a fundamental operation, divide by zero is nearly always an error in non-specialist code, and non-specialists really don't want to see infinities cropping up in their calculations.

So by all means discuss math.lgamma. But be very careful translating any intuitions you have over that across to division.

Here's a question.

1.0 / 2.0 is 0.5. No question there. 1 / 2 is *also* 0.5. So integer division can give float values. And should give "the same result" (mathematically). 1.0 / 0.0 is being debated, but let's say we agree that it should produce inf, because that's IEEE-754. Now, what about 1 / 0? Do we violate the principle that led to 1 / 2 being 0.5? Or do we allow this to generate a floating infinity? 1 // 0 has to give ZeroDivisionError, as there's no possible *integer* result. But now I find myself uncomfortable that 1//0 raises an exception but 1/0 doesn't.

And as soon as we start considering integer division, we're talking about breaking a *vast* amount of code.

As I said above, pick your preferred form of inconsistency. But don't expect to get perfect consistency, it's not an option.

I disagree. This is entirely on the practical side of things!

Calculations on the extended real line are "just calculations", as are calculations with IEEE 754 floats. Any attentive high school student can learn to do them (at least with the help of a computer for correct rounding in the case of IEEE 754 floats :-). There's no theory to discuss (except for terminology like "true infinity").

But extended reals are only one thing you might be trying to model with Python's floating point. Non-specialists are more likely to have an (imperfect) mental model of a calculator. Which typically errors on divide by zero.

The question of whether Python diverges from IEEE 754 (which turns on whether IEEE 754 recommends that you raise exceptions or return inf/nan but not both), and the question of whether the IEEE 754 model of "overflow as infinity" is intuitive/useful to users of Python who *don't* use NumPy, are the questions under discussion here.

Python floats exist in a context where they need to interact "consistently" with other types. So there's a tension between precisely modeling IEEE-754 and fitting with the rest of the language. In general, I'm in favour of floats accurately following IEEE-754, but we need to be careful not to be too dogmatic at the edge cases.

Also, we need to remember that IEEE-754 might define rules for how division works, but it doesn't (can't) mandate how Python spells that operation, so in theory, we could have math.iee743_div for "a strictly conforming" version. And once we start thinking about that it becomes clear that "which set of rules gets to be called /" is a matter of user friendliness as much as "correctness".

Now, to be fair, there is a practicality beats purity argument. It can be argued (I think Ben or maybe Chris A alluded to this) that "overflows usually' just happen but division by zero usually' is a logic error". Therefore returning inf in the case of overflow (and continuing the computation), and raising on zero division (stopping the computation and getting the attention of the user), is the pragmatic sweet spot. I disagree, but it's a viable argument.

That's probably my main point, coupled with the points that "division, as a language built in operator, is very different from functions in the math module", and "division is polymorphic, and consistent behaviour across types is an extra consideration that math functions don't need to be concerned about".

Footnotes: [1] If you haven't read The Mote in God's Eye, that's the third hand of the aliens, which is big, powerful, clumsy, and potentially deadly. Pretty much the way I think of "inf"!

Yep, spot on!

Paul _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4INMMQ... Code of Conduct: http://python.org/psf/codeofconduct/

1 / 0

<raises error>

1 / 0.0

inf

Is not true as since python 3 has adopted true division 1/1 returns 1.0 so 1/0 would also return inf.

Steve Barnes

Sent from Mailhttps://go.microsoft.com/fwlink/?LinkId=550986 for Windows 10

From: Cade Brownmailto:brown.cade@gmail.com Sent: 15 September 2020 15:05 To: Paul Mooremailto:p.f.moore@gmail.com Cc: python-ideasmailto:python-ideas@python.org Subject: [Python-ideas] Re: 'Infinity' constant in Python

To sum up these discussions, I think it should be said that perhaps a look should be taken at the structure of math-based errors and exceptions, but this discussion should be moved to a new thread on the mailing list perhaps. (I agree that the exceptions make little sense, and I have noticed this)

I'd just like to add that under many circumstances, division by 0 makes perfect sense. For example, in the Riemann Sphere (https://en.wikipedia.org/wiki/Riemann_sphere), 1/0 == infinity (of course, this is not a signed infinity, but rather a single infinity, sometimes called 'complex infinity')

And, under complete euclidean division, it makes sense to describe `x // 0 == 0` and `x % 0 == x`, so that:

(a, b) := (x // y, x % y) implies x = a * y + b

However, should Python cater to these use cases? I don't think so, because most users are committing some sort of error when they divide by zero, and Python should make them acknowledge that explicitly.

Most users aren't abstract theorists. Python shouldn't assume they are

Additionally, not raising an exception on division by float zero would mean the following operations behave vastly differently:

1 / 0

<raises error>

1 / 0.0

inf

This would also be very unexpected

---- Cade Brown Research Assistant @ ICL (Innovative Computing Laboratory) Personal Email: brown.cade@gmail.commailto:brown.cade@gmail.com ICL/College Email: cade@utk.edumailto:cade@utk.edu

On Tue, Sep 15, 2020 at 7:02 AM Paul Moore <p.f.moore@gmail.commailto:p.f.moore@gmail.com> wrote: On Tue, 15 Sep 2020 at 10:29, Stephen J. Turnbull <turnbull.stephen.fw@u.tsukuba.ac.jpmailto:turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Paul Moore writes:

On Tue, 15 Sep 2020 at 08:12, Stephen J. Turnbull <turnbull.stephen.fw@u.tsukuba.ac.jpmailto:turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:

Ben Rudiak-Gould writes:

1./0. is not a true infinity.

- What a "true infinity" is. Are we talking solely about IEEE-754?

OK, so to me, 1.0 / 0.0 *is* a "true infinity" in that sense. If you divide "one" by "zero" the only plausible interpretation - if you allow infinity in your number system - is that you get infinity as a result. Of course that just pushes the question back to whether you mean (mathematical) "one" and "zero" when you make that statement.

I get that Ben is actually saying "things that round to 1" and "things that round to 0", but at that point error propagation and similar details come into play, making even equality a somewhat vague concept.

OK.

- What do 1.0 and 0.0 mean? The literals in Python translate to
Except that application is not consistent. That was the point of Ben's post.

Again OK, but in the face of rounding rules, many "obvious" mathematical properties, such as associativity and distributivity, don't hold. So we have to be *very* careful when inferring equivalences like the one you use below, a * b = c => 1.0 / (a * b) = 1.0 / c.

Note that I'm not saying here that Python's behaviour might not be inconsistent, but rather that it's not obvious (to me, at least) that there is an intuitively consistent set of rules - so Python has chosen one particular way of being inconsistent, and the question is more about whether we like an alternative form of in