Python decimal. Десятичная точность не соответствует wolfram alpha

У меня есть следующий код Python:

In [1]: import decimal

In [2]: decimal.getcontext().prec = 80

In [3]: (1-decimal.Decimal('0.002'))**5
Out[3]: Decimal('0.990039920079968')

Разве он не должен соответствовать 0.99003992007996799440405766290496103465557098388671875 в соответствии с этим http://www.wolframalpha.com/input/?i=SetPrecision%5B%281+-+0.002%29%5E5%2C+80%5D ?


person prgDevelop    schedule 08.11.2013    source источник


Ответы (4)


Wolfram alpha на самом деле здесь неправ.

(1 - 0.002) ** 5

ровно 0.990039920079968.

Вы можете убедиться в этом, просто оценив, что после . есть 15 цифр, что соответствует 5 * 3, где 3 — это количество цифр после . в выражении (1 - 0.002). После 15-го по определению не может быть никакой цифры.

Редактировать

Еще немного покопавшись, я нашел кое-что интересное:

Эта нотация Decimal('0.002') создает фактическое десятичное число с этим точным значением. При использовании Decimal(0.002) десятичное число создается из числа с плавающей запятой, а не из строки, что создает неточность. Используя это обозначение, исходная формула:

(1-decimal.Decimal(0.002))**5

Возвращает Decimal('0.99003992007996799979349352807411754897106595345737537649055432859002826694496107', что действительно на 80 цифр больше, чем ., но отличается от альфа-значения wolfram.

Это, вероятно, вызвано разницей в точности между представлением с плавающей запятой в python и wolfram alpha, и является еще одним признаком того, что wolfram alpha использует числа с плавающей запятой, когда используется SetPrecision.

Примечание: прямой запрос результата возвращает правильное значение (см. http://www.wolframalpha.com/input/?i=%281+-+0.002%29%5E5).).

person njzk2    schedule 08.11.2013
comment
fwiw wolframalpha получает это точно, если вы не переносите выражение в заданную точность.. - person agentp; 09.11.2013

Вот что здесь происходит: поскольку это похоже на синтаксис языка программирования Mathematica, WolframAlpha интерпретирует входные данные SetPrecision[(1 - 0.002)^5, 80] как исходный код Mathematica, который переходит к оценке. В Mathematica, как предполагали другие в других ответах, 0,002 - это буквальное значение с плавающей запятой машинной точности. Возникает ошибка округления. Наконец, SetPrecision приводит результирующее значение машинной точности к ближайшему значению точности 80.

Чтобы обойти это, у вас есть несколько вариантов.

  1. Вы можете попытаться заставить WolframAlpha не думать, что вы вводите код из языка программирования Mathematica, чтобы он творил свою собственную магию. Как упоминалось в njzk2, ввод (1 - 0,002)^5 сделает это.
  2. В коде Mathematica, который вы просите оценить WolframAlpha, вы можете ввести литерал бесконечной точности вместо литерала машинной точности 0,002. Есть несколько способов, но вот один: SetPrecision[(1 - 2*^-3)^5, 80].

Наконец, я хочу отметить, что в Mathematica и, соответственно, в запросе WolframAlpha, состоящем из кода Mathematica, обычно требуется N (документация), а не SetPrecision. Они часто похожи (в данном случае идентичны), но есть тонкая разница:

  • SetPrecision[..., n] сначала устанавливает для всех вложенных чисел точность n, а затем оценивает все (возникает ошибка округления)
  • N[..., n] постоянно пытается использовать SetPrecision с все большей и большей точностью, пока окончательная ошибка округления почти наверняка не станет меньше n.

N работает немного сложнее, но дает вам правильное количество правильных цифр (при условии, что ввод достаточно точен).

Итак, мое последнее предложение по использованию WolframAlpha для выполнения этого расчета с помощью кода Mathematica: N[(1 - 2*^-3)^5, 80].

person Andrew Moylan    schedule 09.11.2013
comment
Спасибо за ваш комментарий. У меня есть еще одна проблема при попытке вычислить это выражение: 100 * (1 - 0,002) ^ 5 * (1 - 0,005) * (1 - 0,006) * 3,5. Mathematica почему-то округляет число до 342,7127137548418, а веб-сайт выдает правильный ответ wolframalpha.com/ input/?i=100*%281+-+0,002%29%5E5*%281+-+0,005%29*%281+-+0,006%29*3,5 Думаю, это происходит по той же причине, по которой вы указано здесь, но есть ли способ исправить это? - person prgDevelop; 09.11.2013
comment
Рецепт для исправления такой же: замените 4 литерала машинной точности с плавающей запятой на точные или высокоточные литералы. Для высокой точности используйте, например, 3,5`80. Для точности используйте 35/10 или SetPrecision[3.5, Infinity]. Что использовать (высокая точность или точность), конечно, зависит от того, насколько хорошо вы действительно знаете это значение! - person Andrew Moylan; 09.11.2013

wolfram неверен, попробуйте его в степени один и вы получите 0.9979999999999999982236431605997495353221893310546875 вместо 0.998. Вероятно, они используют числа с плавающей запятой.

person cmd    schedule 08.11.2013

Следуя ответу Эндрюса, это результат того, что точность введенного литерала считается машинной точностью до того, как директива SetPrecision доберется до нее.

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

SetPrecision[(1-.002`80)^5, 80]

Выдает желаемый результат.

Для тех, кто еще не следит, вы также можете ввести все нули.

 SetPrecision[(1-.0020000000000000000000000...0000)^5, 80]

Они работают в альфе и математике.

person agentp    schedule 09.11.2013