Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-126061: Add PyLong_IsPositive/Zero/Negative() functions #126065

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
36 changes: 36 additions & 0 deletions Doc/c-api/long.rst
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,42 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. versionadded:: 3.14


.. c:function:: int PyLong_IsPositive(PyObject *obj)

Check if the integer object *obj* is positive.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Check if the integer object *obj* is positive.
Check if the integer object *obj* is strictly positive.

Maybe add:

   Check if the integer object *obj* is strictly positive: if *obj* > ``0``.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is no ambiguity. Positive is for, well, being strictly positive. Else we would use something like "nonnegative".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, zero is a positive number. "strictly positive" is used in a few places in Python:

Modules/_bz2module.c:    /* data_size is strictly positive, but because we repeatedly have to
Modules/_io/bufferedio.c:            "buffer size must be strictly positive");
Modules/_io/textio.c:                        "a strictly positive integer is required");
Modules/zlibmodule.c:    /* data_size is strictly positive, but because we repeatedly have to
Python/gc.c:   objects that can be reached directly from outside must have strictly positive
Python/gc.c:   by the reachable objects (the ones with strictly positive reference count).
Python/sysmodule.c:                        "switch interval must be strictly positive");

An alternative is to say "Check if the integer is greater than zero".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, zero is a positive number.

Uh, it doubt I'm able to find math source with this meaning. But a lot for a different opinion:
https://mathworld.wolfram.com/PositiveInteger.html
https://mathworld.wolfram.com/PositiveNumber.html
https://en.wikipedia.org/wiki/Integer

and

$ git grep positive Modules/mathmodule.c Modules/cmathmodule.c|wc -l
11

There is another story: whether 0 is a natural number or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've applied this advice to positive and negative. Maybe that's more appropriate. Maybe victor meant it more purely (it's very positive💯).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's very positive

Also it's very negative:D

Lets just stick with math terminolgy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rruuaanng, please don't mark unresolved conversations as resolved.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you dislike strictly, I suggest:

Suggested change
Check if the integer object *obj* is positive.
Check if the integer object *obj* is positive: greater than zero.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel this addition is needed.

But at least this form is less confusing than "strictly positive". Maybe: "Check if the integer object obj is positive, i.e. greater than zero."


On success, return 1 if *obj* is positive, and 0 otherwise.

On failure, return -1 with an exception set. This function always succeeds
if *obj* is a :c:type:`PyLongObject` or its subtype.
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved

.. versionadded:: 3.14
skirpichev marked this conversation as resolved.
Show resolved Hide resolved


.. c:function:: int PyLong_IsNegative(PyObject *obj)

Check if the integer object *obj* is negative.

On success, return 1 if *obj* is negative, and 0 otherwise.

On failure, return -1 with an exception set. This function always succeeds
if *obj* is a :c:type:`PyLongObject` or its subtype.

.. versionadded:: 3.14
skirpichev marked this conversation as resolved.
Show resolved Hide resolved


.. c:function:: int PyLong_IsZero(PyObject *obj)

Check if the integer object *obj* is zero.

On success, return 1 if *obj* is zero, and 0 if it is non-zero.

On failure, return -1 with an exception set. This function always succeeds
if *obj* is a :c:type:`PyLongObject` or its subtype.

.. versionadded:: 3.14
skirpichev marked this conversation as resolved.
Show resolved Hide resolved


.. c:function:: PyObject* PyLong_GetInfo(void)

On success, return a read only :term:`named tuple`, that holds
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ New Features
an interned string and deallocate it during module shutdown.
(Contribued by Eddie Elizondo in :gh:`113601`.)

* Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative`
and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject`
is positive, negative, or zero.
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
(Contribued by James Roy in :gh:`126061`.)
skirpichev marked this conversation as resolved.
Show resolved Hide resolved

* Add new functions to convert C ``<stdint.h>`` numbers from/to Python
:class:`int`:

Expand Down
18 changes: 18 additions & 0 deletions Include/cpython/longobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnsignedNativeBytes(const void* buffer,
PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op);
PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op);

/* PyLong_IsPositive. Check if the integer object is positive.
- On success, return 1 if *obj is positive, and 0 otherwise.
- On failure, set an exception, and return -1. */
PyAPI_FUNC(int) PyLong_IsPositive(PyObject *obj);

/* PyLong_IsNegative. Check if the integer object is negative.
- On success, return 1 if *obj is negative, and 0 otherwise.
- On failure, set an exception, and return -1. */
PyAPI_FUNC(int) PyLong_IsNegative(PyObject *obj);

/* PyLong_IsZero. Check if the integer object is zero.
- On success, return 1 if *obj is zero, and 0 if it is non-zero.
- On failure, set an exception, and return -1. */
PyAPI_FUNC(int) PyLong_IsZero(PyObject *obj);
skirpichev marked this conversation as resolved.
Show resolved Hide resolved

/* PyLong_GetSign. Get the sign of an integer object:
0, -1 or +1 for zero, negative or positive integer, respectively.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative`
and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject`
is positive, negative, or zero.
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
30 changes: 30 additions & 0 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,36 @@ PyLong_AsUnsignedLongMask(PyObject *op)
return val;
}

int
PyLong_IsPositive(PyObject *obj)
{
if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_TypeError, "expect int, got %T", obj);
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
return -1;
}
return _PyLong_IsPositive((PyLongObject *)obj);
}

int
PyLong_IsNegative(PyObject *obj)
{
if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_TypeError, "expect int, got %T", obj);
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
return -1;
}
return _PyLong_IsNegative((PyLongObject *)obj);
}

int
PyLong_IsZero(PyObject *obj)
{
if (!PyLong_Check(obj)) {
PyErr_Format(PyExc_TypeError, "expect int, got %T", obj);
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
rruuaanng marked this conversation as resolved.
Show resolved Hide resolved
return -1;
}
return _PyLong_IsZero((PyLongObject *)obj);
}

int
_PyLong_Sign(PyObject *vv)
{
Expand Down
Loading