Проблемы с Python с math.floor: int слишком велик для конвертации в float - PullRequest
3 голосов
/ 12 июня 2019

Я хотел бы рассчитать (^2 ^ (1918) * π⌋ + 124476) в Python, но я получаю эту ошибку, когда я делаю это, используя следующий код:

b = math.floor((2**1918) * math.pi) + 124476
print(b)

OverflowError: int слишком велика для преобразования в число с плавающей точкой

Как вы можете заставить это работать? В конце я просто хотел бы, чтобы все было шестнадцатеричным (если это помогает ответить на мой вопрос), но на самом деле я сначала пытался получить его как целое число:)

Ответы [ 4 ]

3 голосов
/ 12 июня 2019

Я думаю, что проблему можно решить, не прибегая к высокоточной арифметике. floor(n.something + m) где m и n - целые числа, равные floor(n.something) + m. Таким образом, в этом случае вы ищете floor(2**1918 * pi) плюс целое число (а именно 124476). floor(2**whatever * pi) - это только первые whatever + 2 биты числа Пи. Так что просто посмотрите на первые 1920 битов числа Пи, добавьте биты для 124476 и выведите их в виде шестнадцатеричных цифр.

Алгоритм spigot может генерировать цифры числа pi без использования произвольной точности. Быстрый поиск в Интернете, кажется, нашел некоторые реализации Python для генерации цифр в базе 10. Я ничего не видел в базе 2, но формула Плуффа генерирует 16 цифр, если я не ошибаюсь.

3 голосов
/ 12 июня 2019

Правильное решение действительно зависит от того, насколько точны результаты. Поскольку 2 ^ 1918 уже слишком велико как для стандартных целочисленных, так и для контейнеров с плавающей запятой, невозможно выполнить прямые вычисления без потери точности до ~ 10 ^ 300.

Чтобы вычислить желаемый результат, вы должны использовать методы вычисления произвольной точности. Вы можете реализовать алгоритмы самостоятельно или использовать одну из доступных библиотек.

Если вы ищете целую часть выражения, для точного хранения результатов потребуется около 600 десятичных знаков. Вот как вы можете получить его, используя mpmath :

from mpmath import mp
mp.dps = 600
print(mp.floor(mp.power(2, 1918)*mp.pi + 124476))

74590163000744215664571428206261183464882552592869067139382222056552715349763159120841569799756029042920968184704590129494078052978962320087944021101746026347535981717869532122259590055984951049094749636380324830154777203301864744802934173941573749720376124683717094961945258961821638084501989870923589746845121992752663157772293235786930128078740743810989039879507242078364008020576647135087519356182872146031915081433053440716531771499444683048837650335204793844725968402892045220358076481772902929784589843471786500160230209071224266538164123696273477863853813807997663357545.0

Далее, все, что вам нужно сделать, это преобразовать его в шестнадцатеричное представление (или извлечь гекс из его внутренней двоичной формы), что является вопросом для другого предмета:)

3 голосов
/ 12 июня 2019

Основная проблема в том, что говорится в сообщении.Целые числа Python могут быть сколь угодно большими, даже больше, чем диапазон с плавающей точкой.2**1918 в десятичном виде содержит 578 значащих цифр и намного больше, чем наибольшее число с плавающей запятой, которое может представлять ваше оборудование IEEE754.Так что вызов просто не получается.

Вы можете попробовать посмотреть на модуль mpmath.Он предназначен для арифметики с плавающей запятой за пределами возможностей, которые могут выполнять обычные аппаратные средства.

2 голосов
/ 12 июня 2019

Проблема в том, что (2**1918) * math.pi пытается преобразовать целое число в 64-битную точность с плавающей запятой, которая недостаточно велика. Вы можете преобразовать math.pi в дробь , чтобы использовать произвольную точность.

>>> math.floor((2**1918) * fractions.Fraction(math.pi) + 124476)
74590163000744212756918704280961225881025315246628098737524697383138220762542289800871336766911957454080350508173317171375032226685669280397906783245438534131599390699781017605377332298669863169044574050694427882869191541933796848577277592163846082732344724959222075452985644173036076895843129191378853006780204194590286508603564336292806628948212533561286572102730834409985441874735976583720122784469168008083076285020654725577288682595262788418426186598550864392013191287665258445673204426746083965447956681216069719524525240073122409298640817341016286940008045020172328756796

Обратите внимание, что к вычислениям применяется произвольная точность; math.pi определяется только с 64-битной точностью с плавающей запятой. Используйте внешнюю библиотеку, такую ​​как mpmath, если вам нужно точное значение.

Чтобы преобразовать это в шестнадцатеричную строку, используйте hex или строковый формат:

>>> hex(math.floor((2**1918) * fractions.Fraction(math.pi) + 124476))
'0xc90fdaa22168c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e63c'
>>> '%x' % math.floor((2**1918) * fractions.Fraction(math.pi) + 124476)
'c90fdaa22168c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e63c'
>>> f'{math.floor((2**1918) * fractions.Fraction(math.pi) + 124476):X}'
'C90FDAA22168C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E63C'

Для строковых форматов x предоставляет строчные буквы в шестнадцатеричном формате, тогда как X обеспечивает прописные буквы.

...