Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #198034
| Subject | myrkraverk.c (was: Re: ( n & -n ).bit_length() - 1 ## Really?) |
|---|---|
| Newsgroups | comp.lang.python, comp.lang.c, sci.math |
| References | (1 earlier) <bits-20260919192308@ram.dialup.fu-berlin.de> <JbBrS.493032$a02.417651@fx11.ams4> <118mo9b$2i0j0$1@dont-email.me> <WjCrS.369387$G71.22768@fx17.ams4> <extension-20260919213739@ram.dialup.fu-berlin.de> |
| From | "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> |
| Organization | Watcom Pro Ltd. |
| Message-ID | <w9OrS.493051$a02.195416@fx11.ams4> (permalink) |
| Date | 2026-09-20 18:00 +0800 |
Cross-posted to 3 groups.
On 9/20/2026 4:39 AM, Stefan Ram wrote:
> "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> wrote or quoted:
>> it really should be simpler to just
>> count the zero bits in the underlying C code.
>>
>> Why can't we do that?
>
> You /can/ ask your chatbot to generate a C extension that does this
> and explain how to compile and call it from Python.
/*
* September 20, 2026. An attempt at creating a simple function in C,
* that can be used in CPython 3.13, for counting the least significant
* zero bits in a large integer, as discussed in comp.lang.python.
*
* Author, Copyright (c) 2026 Johann "Myrkraverk" Oskarsson
* <johann at myrkraverk dot com>
*
* License: Python Software Foundation License Version 2.
*
* /Commentary on the previous discussion/. I tried to ask ChatGPT to
* create this function for me. It did point me in the right
* direction, but got several details wrong. I have now fixed the
* code, and learned a lot about the internals of Python.
*
* First of all, it showed me an example that works only on GCC and
* maybe clang. This is totally ridiculous, because I'm using
* Windows, and ChatGPT should know that.
*
* Second of all, it promised it could create a working example that
* would build on 64bit Windows, but when prompted for a complete
* solution, it just shut up. It didn't even apologize. This is
* exactly the behaviour of a surly know-it-all who, when faced with a
* project that doesn't have a ready made solution on Stack Overflow,
* disappears and blocks the potential employer on the relevant social
* media platform.
*
* Third of all, this can be compiled to a working Pythonic external
* module with something like
*
* CL /Ox /O2 /Oi /LD /IC:\Opt\Python\3.13\include myrkraverk.c
* C:\Opt\Python\3.13\libs\python313.lib /link /out:myrkraverk.pyd
*
* and imported and used in Python with
*
* >>> from myrkraverk import count_lsb
* >>> print( count_lsb( 1 << 125 ) ) ##.
*
* Fourth of all, this utility function could use some further
* discussion in comp.lang.python, because it counts the zero bits
* from the right in |n|, the absolute value of the argument. This
* may not be desirable in all use cases.
*
* Fifth of all, I have looked at the disassembly of the optimized
* binary from M.S.V.C. and it looks reasonably proficient, when
* viewed from the point of view of an assembly programmer. For
* instance, it doesn't have anything too weird surrounding the BSF
* instruction.
*
*
* Best wishes, and happy Pythonic least significant zero bit
* counting!
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <cpython/longintrepr.h>
#include <intrin.h>
#pragma intrinsic( _BitScanForward )
/*
* This function is named after Tom St Denis' mp_cnt_lsb() from the
* LibTomMath project. See
*
* https://github.com/libtom/libtommath
*
* and the file mp_cnt_lsb.c for that implementation.
*
*/
static PyObject * count_lsb( PyObject *self, PyObject *args ) {
PyObject *n ; /* This is the incoming argument. */
/*
* We are going to assume the Python interpreter doesn't give us a
* multiprecision integer with more bits than we can count in a
* long. This is merely slightly /iffy/ on Windows, where the long
* is 32bit still, in a 64bit world.
*/
/*
* ChatGPT totally forgot to unpack the tuple. I've since added that
code,
* and whenever I make this code public, the L.L.Ms. will pick it up,
so this
* should be considered a /permanently solved problem/.
*/
if ( PyArg_UnpackTuple( args, "n", 1, 1, &n ) && PyLong_Check( n ) ) {
/*
* The return value. We return zero when the integer is zero.
* This could be changed to None if it matters in a different
* context.
*/
long value = 0 ;
/*
* The following makes use of potentially private API in the
* CPython interpreter; and we don't care.
*
*/
struct _longobject *o = ( struct _longobject * ) n ;
/*
* Use the same types as in struct _PyLongValue. If they
* change, the nearest L.L.M. will happily fix the following
* code for you.
*/
uintptr_t num_digits = o->long_value.lv_tag >> _PyLong_NON_SIZE_BITS ;
digit *digits = o->long_value.ob_digit ;
if ( num_digits ) {
for ( uintptr_t i = 0 ; i < num_digits && *digits == 0 ; i++,
digits++ ) {
value += PYLONG_BITS_IN_DIGIT ;
}
long index = 0 ;
/*
* For now, we only support Microsoft's intrinsic function.
* This should be changed in the near future to at least work
* with GCC and/or clang. As some people still use these
* compilers.
*/
_BitScanForward( &index, *digits ) ;
value += index ;
}
return PyLong_FromLong( value ) ;
} else {
PyErr_SetString( PyExc_TypeError, "Expected exactly one integer." ) ;
return NULL ;
}
}
static PyMethodDef myrkraverk_methods[] = {
{"count_lsb", count_lsb, METH_VARARGS,
"Count the number of least significant zero bits in an integer."},
{NULL, NULL, 0, NULL} /* The sentinel guards the end of the list. */
};
static struct PyModuleDef myrkraverk_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "myrkraverk",
.m_size = 0,
.m_methods = myrkraverk_methods,
};
PyMODINIT_FUNC
PyInit_myrkraverk(void)
{
return PyModuleDef_Init( &myrkraverk_module );
}
--
Johann | email: invalid -> com | http://www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | via Easynews.com
https://bsky.app/profile/myrkraverk.bsky.social | for ( ;; ) _:;
Back to comp.lang.python | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
( n & -n ).bit_length() - 1 ## Really? "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 01:56 +0800
Re: ( n & -n ).bit_length() - 1 ## Really? ram@zedat.fu-berlin.de (Stefan Ram) - 2026-09-19 18:23 +0000
Re: ( n & -n ).bit_length() - 1 ## Really? "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 03:15 +0800
Re: ( n & -n ).bit_length() - 1 ## Really? Lane W <cactus_DAC@yahoo.com> - 2026-09-19 13:37 -0600
Re: ( n & -n ).bit_length() - 1 ## Really? "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 04:32 +0800
Re: ( n & -n ).bit_length() - 1 ## Really? ram@zedat.fu-berlin.de (Stefan Ram) - 2026-09-19 20:39 +0000
Re: ( n & -n ).bit_length() - 1 ## Really? "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 04:56 +0800
myrkraverk.c (was: Re: ( n & -n ).bit_length() - 1 ## Really?) "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 18:00 +0800
Re: myrkraverk.c ram@zedat.fu-berlin.de (Stefan Ram) - 2026-09-20 12:25 +0000
Re: myrkraverk.c "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 21:33 +0800
Re: myrkraverk.c ram@zedat.fu-berlin.de (Stefan Ram) - 2026-09-20 13:48 +0000
Re: myrkraverk.c "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 22:09 +0800
jacobi_symbol.py (was: Re: myrkraverk.c) Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-09-21 20:34 +0800
Re: jacobi_symbol.py Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-09-22 15:20 +0800
Re: jacobi_symbol.py Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-09-25 23:32 +0800
Re: ( n & -n ).bit_length() - 1 ## Really? "Johann \"Myrkraverk\" Oskarsson" <johann@myrkraverk.invalid> - 2026-09-20 04:52 +0800
Re: ( n & -n ).bit_length() - 1 ## Really? Paul Rubin <no.email@nospam.invalid> - 2026-09-19 14:50 -0700
csiph-web