Тонкости модуля Python Math - PullRequest
1 голос
/ 07 февраля 2012

Я экспериментировал со стандартным математическим модулем Python и столкнулся с некоторыми тонкими трудностями. Например, я заметил следующее поведение относительно неопределенных форм:

0**0

>>> 1

def inf():
    return 1e900
    # Will return inf

inf()**inf()

>>> inf

И другие подобные аномалии. Я пишу калькулятор, и я хотел бы, чтобы он был математически точным. Что я могу с этим поделать? Или есть какой-то способ обойти это? Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 07 февраля 2012

Согласно Вольфраму (цитируя Кнута), в то время как 0 ** 0 является неопределенным, иногда оно задается как 1. Это потому, что в некоторых случаях полезно сохранять выражение «x ** 0 = 1» как истинное во всех случаях. Еще интереснее то, что Python также будет считать NaN ** 0 равным 1.

http://mathworld.wolfram.com/Power.html

В случае бесконечности ** бесконечность, вы на самом деле не имеете дело с математической концепцией бесконечности здесь (где это было бы неопределенным), а скорее с числом, которое слишком велико и переполнилось. Таким образом, все, что говорится в этом утверждении, так это то, что число, которое огромно для силы другого числа, все еще является числом, которое огромно.

Edit: я не думаю, что в Python возможно перегрузить встроенный тип (такой как float), поэтому перегрузить оператор float .__ pow __ (x, y) напрямую. Что вы могли бы сделать, это определить свою собственную версию float.

class myfloat(float):
    def __pow__(x,y):
        if(x==y==0):
            return 'NaN'
        else:
            return float.__pow__(x,y)

m = myfloat(0)
m**0

Не уверен, что это именно то, что вы ищете.

2 голосов
/ 07 февраля 2012

Нет ничего плохого в вашем первом примере.0**0 часто определяется как 1.

Второй пример касается точности двойных чисел.1E900 превышает максимальное положительное значение (скорее всего, 64-разрядного) двойного числа.Если вы хотите удвоить значение за пределами этого диапазона, вам придется заглянуть в библиотеки.К счастью, в Python есть один встроенный: десятичный модуль .

Например:

from decimal import Decimal
d = Decimal('1E900')
f = d + d
print(f)
>>> 2E900
1 голос
/ 08 февраля 2012

Хорошо возвращать NaN для 0**0 почти всегда бесполезно, и многие алгоритмы избегают особых случаев, если принять 0**0 == 1.Поэтому, хотя это может быть математически не идеально - мы говорим об IEEE-754 здесь, математическая точность - это наименьшая из наших проблем [1]

Но если вы хотите изменить это, это довольно просто.Следующее работает, как и ожидалось, в Python 3.2:

def my_pow(x, y):
    if y == 0: return 'NaN'
    return float.__pow__(float(x), y)

pow = my_pow

[1] Следующий код теоретически может выполнить ветвь if с процессорами x86 (ну, по крайней мере, в C и co):

float x = sqrt(y);
if (x != sqrt(y)) printf("Surprise, surprise!\n");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...