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

[C API] Add PyLong_GetNumBits() function #119714

Closed
vstinner opened this issue May 29, 2024 · 11 comments
Closed

[C API] Add PyLong_GetNumBits() function #119714

vstinner opened this issue May 29, 2024 · 11 comments
Labels
topic-C-API type-feature A feature request or enhancement

Comments

@vstinner
Copy link
Member

vstinner commented May 29, 2024

Feature or enhancement

In Python 3.13 alpha1, I removed the private _PyLong_NumBits() function. It seems like this function is used by pywin32 and MariaDB projects: see issue gh-119336.

I propose to add a public function to replace it:

Py_ssize_t _PyLong_GetNumBits(PyObject *obj);
  • Return the number of bits on success: greater than or equal to zero.
  • Set an exception and return -1 on error.
  • Set an OverflowError exception, and return -1 if the number of bits doesn't fit into Py_ssize_t.

The C function is similar to the Python int.bit_length() method.

See also the proposed PyLong_GetSign() function.

Linked PRs

@serhiy-storchaka
Copy link
Member

Why not return (size_t)-1 as indicator of error? It would be more consisting with the existing C API.

@encukou
Copy link
Member

encukou commented May 29, 2024

We have a size type that can be negative to express errors. IMO, this should be Py_ssize_t PyLong_GetNumBits(PyObject *obj);.

Can we first add the underscored version back? IMO, we should design the API first, and only then start removing a function that's been there since 2003 and is used in popular software like mariadb or panda3d.
I see no reason to break people's working code. We have a better deprecation mechanism coming up in PEP-743.

vstinner added a commit to vstinner/cpython that referenced this issue May 29, 2024
vstinner added a commit to vstinner/cpython that referenced this issue May 29, 2024
@vstinner
Copy link
Member Author

Can we first add the underscored version back?

The revert is discussed in a separated issue: #119336 I just enabled automerge on its PR: #119418.

First, I wasn't sure that it's worth it to restore it if a single project uses it, since you can easily call PyObject_CallMethod(obj, "bit_length", NULL) in C to get the same value. Since I discovered more projects using it, I proposed to add a public function.

@vstinner
Copy link
Member Author

@serhiy-storchaka:

Why not return (size_t)-1 as indicator of error? It would be more consisting with the existing C API.

@encukou:

We have a size type that can be negative to express errors. IMO, this should be Py_ssize_t PyLong_GetNumBits(PyObject *obj);.

I prefer to return an int to indicate success or error. But since you both prefer to reuse the return value to also indicate an error, I changed the return type to Py_ssize_t (which was my first idea in fact).

@vstinner
Copy link
Member Author

I wrote the PR #119715 to implement the function.

@serhiy-storchaka
Copy link
Member

serhiy-storchaka commented May 29, 2024

Py_ssize_t has a range twice smaller than size_t. Usually this is not a problem if used for size or index, because no object can be larger than PY_SSIZE_T_MAX bytes. But you can create an integer having more than 2**31 bits on 32-bit platform, and even more than 2**32 bits. It is not accident that _PyLong_NumBits uses size_t instead of Py_ssize_t.

It is still limited. This is why int.bit_length does not use it. And this is the reason of not adding the public C API earlier -- it does not support all int objects.

Perhaps returning a 64-bit integer, even on 32-bit platform, can solve the issue. In this case it does not matter whether the return type is signed or unsigned.

@vstinner
Copy link
Member Author

IMO 2**31 limit on a 32-bit system is a reasonable limitation, since Python is slow to manage such very large number. The OverflowError is already documented in the API documentation, we can also suggest calling bit_length() for very large integer.

@vstinner
Copy link
Member Author

we can also suggest calling bit_length() for very large integer

Done in the PR.

@vstinner
Copy link
Member Author

vstinner commented Jun 3, 2024

I created a ticket in the C API Working Group: capi-workgroup/decisions#28

@erlend-aasland
Copy link
Contributor

See also previous slightly related discussion:

vstinner added a commit to vstinner/cpython that referenced this issue Jun 3, 2024
@vstinner
Copy link
Member Author

The C API Working Group rejected this API: PyLong_AsNativeBytes() should be used instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-C-API type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants