Каковы конкретные правила для постоянного свертывания? - PullRequest
3 голосов
/ 02 мая 2019

Я только что понял, что CPython, похоже, обрабатывает константные выражения, которые представляют одно и то же значение, по-разному в отношении константного свертывания. Например:

>>> import dis
>>> dis.dis('2**66')
  1           0 LOAD_CONST               0 (2)
              2 LOAD_CONST               1 (66)
              4 BINARY_POWER
              6 RETURN_VALUE
>>> dis.dis('4**33')
  1           0 LOAD_CONST               2 (73786976294838206464)
              2 RETURN_VALUE

Для второго примера применяется постоянное свертывание, а для первого - нет, хотя оба представляют одно и то же значение. Кажется, это не связано ни со значением показателя степени, ни с величиной результата, так как складываются также следующие выражения:

>>> dis.dis('2.0**66')
  1           0 LOAD_CONST               2 (7.378697629483821e+19)
              2 RETURN_VALUE
>>> dis.dis('4**42')
  1           0 LOAD_CONST               2 (19342813113834066795298816)
              2 RETURN_VALUE

Почему первые два выражения обрабатываются по-разному и, в более общем смысле, каковы конкретные правила, которым CPython следует для константного свертывания?


Проверено на:

$ python3.6 --version
Python 3.6.5 :: Anaconda, Inc.
$ python3.7 --version
Python 3.7.1

1 Ответ

4 голосов
/ 02 мая 2019

Есть нет правил для постоянного сворачивания.Есть только детали реализации.Они изменились раньше, и они изменятся снова.

Черт, вы даже не можете говорить о «поведении Python 3» или «поведении Python 3.6», потому что эти детали реализации изменились между 3.6. 4 и 3,6. 5 .На 3.6.4 пример 2**66 постоянно сворачивается.

Пока, и никто не знает, как долго продлится «сейчас», детали реализации заключаются в том, что в оптимизаторе AST предусмотрены меры предосторожности для предотвращения расходов.слишком много времени или памяти на постоянное сворачивание.Защита для 2**66 или 4**33 основана на количестве битов в LHS и значении RHS:

if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) {
    size_t vbits = _PyLong_NumBits(v);
    size_t wbits = PyLong_AsSize_t(w);
    if (vbits == (size_t)-1 || wbits == (size_t)-1) {
        return NULL;
    }
    if (vbits > MAX_INT_SIZE / wbits) {
        return NULL;
    }
}

MAX_INT_SIZE равно #define d.ранее как 128. Поскольку 2 является 2-битным числом, а 4 является 3-битным числом, расчетный размер результата меньше для 4**33, поэтому он проходит проверку и получает постоянное свертывание.

В Python 3.6.5 детали реализации в основном схожи, но это постоянное свертывание происходит в оптимизаторе глазкового отверстия вместо оптимизатора AST, которого нет в 3.6.5.

На Python 3.6.4 гарантия предварительной проверки не существует.Оптимизатор глазка будет отбрасывать слишком большие постоянные результаты свертывания после их вычисления, что приведет к другим порогам, чем предварительные проверки.

...