Поддержка Python C-API int128 - PullRequest
       46

Поддержка Python C-API int128

0 голосов
/ 20 января 2019

В Python можно обрабатывать очень большие целые числа (например, uuid.uuid4().int.bit_length() дает 128), но самая большая структура данных int, которую предлагает документация C-API , равна long long, и это 64-бит int.

Я бы хотел получить C int128 от PyLong, но, похоже, для этого нет никаких инструментов. Например, PyLong_AsLongLong не может обрабатывать целые числа python больше 2**64.

  • Есть ли какая-то документация, которую я пропустил, и это на самом деле возможно?
  • В настоящее время это невозможно, но существует какой-то обходной путь? (Я хотел бы использовать инструменты, доступные в C-API Python для long long с int128, например, функцией PyLong_AsInt128AndOverflow).
  • Планируется ли это в следующей версии Python?

1 Ответ

0 голосов
/ 20 января 2019

Существует несколько различных способов доступа к нужному уровню точности.

Системы с 64-разрядными long с часто имеют 128-разрядные long long с.Обратите внимание, что в статье, на которую вы ссылаетесь, написано « не менее 64 бит».Стоит проверить sizeof(long long) на тот случай, если больше ничего не нужно делать.

Предполагая, что это не то, с чем вы работаете, вам придется присмотреться к необработанным PyLongObject,которая на самом деле является typedef частной _longobject структуры.

Необработанные биты доступны через поле ob_digit, длина которого определяется какob_size.Тип данных цифр и фактическое количество загружаемых ими ботинок задаются typedef digit и макросом PYLONG_BITS_IN_DIGIT.Последний должен быть меньше 8 * sizeof(digit), больше 8 и кратен 5 (то есть 30 или 15, в зависимости от того, как была выполнена ваша сборка).

К счастью для вас, есть «недокументированный»метод в C API, который будет копировать байты числа для вас: _PyLong_AsByteArray.Комментарий в longobject.h гласит:

/* _PyLong_AsByteArray: Convert the least-significant 8*n bits of long
   v to a base-256 integer, stored in array bytes.  Normally return 0,
   return -1 on error.
   If little_endian is 1/true, store the MSB at bytes[n-1] and the LSB at
   bytes[0]; else (little_endian is 0/false) store the MSB at bytes[0] and
   the LSB at bytes[n-1].
   If is_signed is 0/false, it's an error if v < 0; else (v >= 0) n bytes
   are filled and there's nothing special about bit 0x80 of the MSB.
   If is_signed is 1/true, bytes is filled with the 2's-complement
   representation of v's value.  Bit 0x80 of the MSB is the sign bit.
   Error returns (-1):
   + is_signed is 0 and v < 0.  TypeError is set in this case, and bytes
     isn't altered.
   + n isn't big enough to hold the full mathematical value of v.  For
     example, if is_signed is 0 and there are more digits in the v than
     fit in n; or if is_signed is 1, v < 0, and n is just 1 bit shy of
     being large enough to hold a sign bit.  OverflowError is set in this
     case, but bytes holds the least-significant n bytes of the true value.
*/

Вы можете получить UUID с чем-то вроде

PyLongObject *mylong;
unsigned char myuuid[16];

_PyLong_AsByteArray(mylong, myuuid, sizeof(myuuid), 1, 0);
...