On 9/20/2026 4:39 AM, Stefan Ram wrote:
"Johann \"Myrkraverk\" Oskarsson" <[email protected]> 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 ( ;; ) _:;
--
https://mail.python.org/mailman3//lists/python-list.python.org

Reply via email to