Эффективный целочисленный размер Python

Например, в C#, C++, Java или JavaScript эффективный размер целого числа составляет 32 бита. Если мы хотим вычислить какое-то большое число, например, 70 бит, мы должны использовать некоторые программные возможности (Арифметика произвольной точности).

Python имеет очень сложное целочисленное внутреннее безграничное представление, и я не могу понять, какой размер int является наиболее эффективным для целочисленной арифметики.

Другими словами, есть ли у нас какой-то размер целого числа, скажем, 64 бита, для эффективного использования целых чисел?

Или неважно, 16, 32, 64 или some random bits count, и Python будет работать для всех этих целых чисел с одинаковой эффективностью?

Короче говоря, Python всегда использует арифметику произвольной точности или для 32\64 использует аппаратную арифметику?


person No Name QA    schedule 16.08.2020    source источник
comment
Вы можете использовать numpy, если размер имеет значение. Здесь вы можете выбрать, например, uint32 и uint64.   -  person Stefan    schedule 16.08.2020
comment
Я не уверен, что вы спрашиваете, целые числа Python не имеют размера, что вы, кажется, уже понимаете?   -  person juanpa.arrivillaga    schedule 16.08.2020
comment
@Stefan или, в качестве альтернативы, вы можете использовать модуль array для примитивных числовых массивов, которого иногда бывает достаточно (если вы собираетесь выполнять какую-либо тяжелую обработку, то, вероятно, вам нужен numpy)   -  person juanpa.arrivillaga    schedule 16.08.2020
comment
Насколько вам известно, битовая длина любого конкретного объекта int является деталью реализации. Я не понимаю, о чем вы здесь спрашиваете, есть ли у нас какой-то размер целого числа, скажем, 64 бита, для эффективного использования целых чисел?   -  person juanpa.arrivillaga    schedule 16.08.2020
comment
@juanpa.arrivillaga у нас есть два вида арифметики. Hardware, для целых чисел с размером меньше или равным слову процессора. Software, когда мы можем вычислять большие числа (больше, чем слово ЦП), но медленно, используя некоторый код. Всегда ли Python использует медленную программную арифметику? Или он использует аппаратную арифметику для 32/64 бит?   -  person No Name QA    schedule 16.08.2020
comment
Вы должны добавить это к своему вопросу, потому что это вопрос о внутренних компонентах CPython.   -  person juanpa.arrivillaga    schedule 16.08.2020
comment
@juanpa.arrivillaga сделано. Вы знаете ответ?   -  person No Name QA    schedule 16.08.2020
comment
Нет, но вот реализация: github.com/python/cpython/ blob/master/Objects/longobject.c РЕДАКТИРОВАТЬ: И здесь, я думаю, реализовано добавление: github.com/python/cpython/blob/   -  person juanpa.arrivillaga    schedule 16.08.2020
comment
@juanpa.arrivillaga Если бы я мог понять реализацию, я бы не задавал здесь вопрос.   -  person No Name QA    schedule 16.08.2020


Ответы (1)


CPython int в Python 3 представлен как массив значений со знаком, где каждый элемент в массиве представляет 15 или 30 битов величины для 32- и 64-битных сборок Python соответственно. Это деталь реализации, но давняя (изначально всегда было 15, но было обнаружено, что удвоить размер и количество используемых битов на цифру в массиве при работе в 64-битных системах было легко). Он имеет оптимизации для ints, которые подходят для одного (или иногда двух) таких значений массива (он извлекает необработанное значение из массива и выполняет одну операцию ЦП, пропуская циклы и алгоритмы, которые применяются к случаю произвольной длины), и на 64 битовые сборки CPython, что в настоящее время означает, что значения с величиной 30 бит или меньше обычно оптимизированы специально (с 60-битными величинами, иногда имеющими быстрые пути).

Тем не менее, редко есть причина принимать это во внимание; Накладные расходы интерпретатора CPython довольно высоки, и довольно сложно представить сценарий, в котором ручное разбиение более крупной операции на более мелкие (с дополнительными накладными расходами интерпретатора для выполнения множества мелких операций на уровне Python) перевешивало бы гораздо меньшую стоимость Python, выполняющего операции на основе массивов (даже без специальных быстрых путей) на уровне C. Все исключения из этого правила будут основываться на не-Python-int-решениях, использующих массивы numpy фиксированного размера для векторизации работы и в значительной степени следуя правилам C на этом этапе (поскольку массивы numpy являются обертками вокруг необработанных массивов C большую часть времени) .

person ShadowRanger    schedule 16.08.2020
comment
Я предполагаю, что пример оптимизации здесь где он проверяет if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) { return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b));} - person juanpa.arrivillaga; 16.08.2020
comment
@juanpa.arrivillaga: Ага. MEDIUM_VALUE — это макрос, который распаковывает один элемент из базового массива (и исправляет его знак, поскольку само значение массива не подписано). Так что это просто распаковка обоих, добавление их с помощью обычной инструкции ЦП, а затем переупаковка в новый int. - person ShadowRanger; 16.08.2020
comment
Означает ли это, что сборка Python 64 эффективно работает с целыми числами только в диапазоне от -2 ^ 29 до 2 ^ 29 -1? - person No Name QA; 16.08.2020
comment
@NoNameQA: диапазон от -2³⁰ - 1 до 2³⁰ - 1; массив содержит 30-битную беззнаковую величину в каждом элементе, а знак кодируется размером массива (отрицательные числа сохраняют отрицательную длину массива). Идея состоит в том, что переполнение не может произойти даже при умножении, когда оба операнда достаточно малы, чтобы поместиться в 32-битном диапазоне, а работа выполняется с 64-битными операндами. 30-битная (вместо 31-битной) вещь связана с относительной легкостью преобразования алгоритмов, которые работали с 15 из 16 бит, простым удвоением всех чисел. - person ShadowRanger; 16.08.2020
comment
Вы можете увидеть эффект с помощью sys.getsizeof; в моей 64-битной сборке sys.getsizeof(-(2**30) - 1) равно 28 (байтам), а sys.getsizeof(-(2**30)) равно 32; массив должен был расширяться, когда старший бит перемещался на 31-й бит. - person ShadowRanger; 16.08.2020
comment
Удивительный ответ! Такое странное поведение. Благодарю вас! - person No Name QA; 16.08.2020
comment
Просто для потомков, я немного опечатался при вводе цифр. Диапазон от -2³⁰ + 1 до 2³⁰ - 1, sys.getsizeof(-(2**30 - 1)) (или, что то же самое, sys.getsizeof(-(2**30) + 1)) имеет размер 28 байт. - person ShadowRanger; 18.08.2020