Неточный логарифм в Python

Я работаю ежедневно с Python 2.4 в моей компании. Я использовал универсальную логарифмическую функцию " log " из стандартной математической библиотеки, и когда я ввел log(2**31, 2), он вернул 31.000000000000004, что показалось мне немного странным.

Я сделал то же самое с другими силами 2, и это сработало отлично. Я запустил " log10(2**31) / log10 (2)", и я получил раунд 31.0

Я попытался запустить ту же исходную функцию в Python 3.0.1, предполагая, что она была исправлена в более продвинутом версия.

Почему это происходит? Возможно ли, что в Python есть некоторые неточности в математических функциях?

7 ответов


Это следует ожидать с компьютерной арифметикой. Он следует определенным правилам, таким как IEEE 754, Это, вероятно, не соответствует математике, которую вы узнали в школе.

Если это на самом деле имеет значение, используйте Python десятичного типа.

пример:

from decimal import Decimal, Context
ctx = Context(prec=20)
two = Decimal(2)
ctx.divide(ctx.power(two, Decimal(31)).ln(ctx), two.ln(ctx))

вы должны прочитать "что каждый компьютерщик должен знать об арифметике с плавающей запятой".

http://docs.sun.com/source/806-3568/ncg_goldberg.html


всегда предположим, что операции с плавающей запятой будут иметь некоторую ошибку в них и проверять равенство с учетом этой ошибки (либо процентное значение, такое как 0.00001%, либо фиксированное значение, такое как 0.00000000001). Эта неточность дана, так как не все десятичные числа могут быть представлены в двоичном формате с фиксированным количеством битов точности.

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


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

В общем, совершенно неправильно предполагать, что операции с плавающей запятой точны, особенно с одной точностью. раздел"проблемы точности" из Википедии с плавающей запятой статья:)


IEEE двойные числа с плавающей запятой имеют 52 бита точности. С тех пор 10^15


Это нормально. Я ожидал бы, что log10 будет более точным, чем log (x, y), поскольку он точно знает, что такое база логарифма, также может быть некоторая аппаратная поддержка для вычисления логарифмов base-10.


на representation (float.__repr__) числа в python пытается вернуть строку цифр как можно ближе к реальному значению, насколько это возможно при обратном преобразовании, учитывая, что арифметика IEEE-754 точна до предела. В любом случае, если вы printed результат, вы бы не заметили:

>>> from math import log
>>> log(2**31,2)
31.000000000000004
>>> print log(2**31,2)
31.0

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

>>> log(1000000,2)
19.931568569324174
>>> print log(1000000,2)
19.9315685693
>>> 1.0/10
0.10000000000000001
>>> print 1.0/10
0.1

usuallyuseless' ответ очень полезен, на самом деле:)