Python: произвольная точность с поплавками

Я попытался вычислить math.exp(9500), но столкнулся с OverflowError: math range error (примерно 6,3e4125). Из этого вопроса кажется, что это связано со слишком большим поплавком, принятый ответ говорит «(...) немного выходит за пределы диапазона двойного числа, поэтому вызывает переполнение».

Я знаю, что Python может работать с произвольно большими целыми числами (длинный тип), есть ли способ таким же образом обрабатывать произвольно большие числа с плавающей запятой?

Редактировать: мой первоначальный вопрос был об использовании целых чисел для вычисления exp(n), но, как сказал Эрик Дюминил, самым простым способом сделать это будет 3**n, который не дает никакого полезного результата. Я понимаю, что этот вопрос может быть похож на этот вопрос.


person potato    schedule 25.07.2017    source источник
comment
Боюсь даже спросить, что за задача потребует вычисления exp(9500)...   -  person EOF    schedule 25.07.2017
comment
Сама проблема не решается, но я многократно выполняю умножение матриц: A * B, но B со временем становится более разреженным, A остается постоянным. Я пытался вычислить количество необходимых умножений в зависимости от разреженности B, в этом случае количество пустых строк B росло логарифмически от 1 до 9500, что дает нам общее количество умножений, которое немного похоже на сумму для i от 1 до n из (A-строк * B-столбцов * ln((exp(9500)/n) * i)).   -  person potato    schedule 25.07.2017
comment
В этом случае вам, вероятно, следует просто упростить формулу: log((exp(9500)/n)*i) равно 9500 + log(i/n) или 9500 + log(i) - log(n). Тогда все будет работать в обычном формате с плавающей запятой двойной точности.   -  person Mark Dickinson    schedule 25.07.2017
comment
@MarkDickinson Правильно! Я совершенно забыл упростить это... Я только что попробовал, и Python больше не жалуется. Тем не менее, та же формула дает мне 3,7323287594132553 * 10 ^ 9 с Python и 3,757328759413250 ... × 10 ^ 9 с Wolfram Alpha. Мне интересно, это просто ошибка округления?   -  person potato    schedule 25.07.2017
comment
@potato: Да, это просто ошибка округления.   -  person Eric Duminil    schedule 26.07.2017


Ответы (3)


Я не думаю, что возможно аппроксимировать exp() целыми числами. Если вы используете 3**n вместо 2.71828182845905**n, ваши расчеты будут совершенно бесполезны.

Одним из возможных решений может быть использование Sympy. Согласно документации:

По сути, нет верхнего предела точности

>>> from sympy import *
>>> exp(9500)
exp(9500)
>>> exp(9500).evalf()
6.27448493490172e+4125

Вы также можете указать желаемую точность:

>>> exp(9500).evalf(1000)
6.274484934901720177929867046175406311474380389941415760684209191232450360090766458256588885184199320756050569665785657269735313171886975309933254563488343491718198237894473901620914303565550450204805537225888529509352754121292701357622411614860860409639719786022989336837263283678476008817556351031696366815467221836948040042378034720460820127399855873232167818091083005170669482845098735176209372328114732133251096196535355946589133977397512846130629857604295369747597459602137604440011394793443041829253598478244189078131130488653468669559814695095974271938947640276013215753183113041899037415404445478806695965167014404297848725756879184380559837391976534521522360723388582608454995349380217499779247330557664230806254642768796486899322646423713763772064068933790640394967085887914192401473425799354391464743910233873602389444180426155866237536459654917521713769608318128404177877383203786348495822099924812081683286880293701785567962687838594752986160305764297117036426951203418854463404773701882e+4125

С exp(9500).evalf(5000) вы даже получите целое число, ближайшее к exp(9500).

person Eric Duminil    schedule 25.07.2017
comment
Большое спасибо, это именно то, что я искал. Кроме того, ваше решение дает гораздо больше, и мой вопрос, вероятно, был написан не очень хорошо, я переписал часть его, чтобы быть более точным и явным. - person potato; 25.07.2017

Вот еще один способ вычислить результат с помощью Python:

exp(9500)

слишком большой.

Но log10(exp(9500)) нет. Вы не можете вычислить это таким образом в Python, но log10(exp(9500)) это log(exp(9500))/ln(10), то есть 9500/ln(10):

>>> from math import log
>>> 9500/log(10)
4125.797578080892
>>> int(9500/log(10))
4125
>>> 10**(9500/log(10) % 1)
6.274484934896202

Таким образом, вы можете вычислить, что exp(9500) равно 6.27448493 * 10**4125 на простом Python, без какой-либо библиотеки!

person Eric Duminil    schedule 26.07.2017

попробуйте long тип.

Тип int был удален из python с версии 3.0.

person Mojann    schedule 25.07.2017
comment
Вы должны указать это в комментариях, а не в ответе. Прочтите документацию, приятель @Mojann - person ; 25.07.2017
comment
Это неверно — int все еще здесь (хотя long, вероятно, больше подходит для этой проблемы.) docs.python.org/3/library/stdtypes.html - person perigon; 25.07.2017
comment
Я задаю этот вопрос, потому что результатом math.exp является число с плавающей запятой. Python уже неявно преобразует int в long, когда это необходимо. - person potato; 25.07.2017
comment
Как целочисленный тип long может помочь в вычислении 2.71828182845905**n? - person Eric Duminil; 25.07.2017