gmpy2 log2 не точный после 16 цифр

При использовании log2() в gmpy2 он не выглядит точным после 16 цифр. Кажется, что он хорошо работает с 15 цифрами, но после этого ответ не является правильным, используя mpz(mpfr(2) ** mpfr(x)). Нужно ли менять точность? Я думал, что Python сам по себе будет точным до 53 цифр.

Кроме того, есть ли способ в gmpy2 использовать операцию логарифма в базах, кроме 10 и 2? Например, база 8 или 16.

1 ответ

Стандартный тип с плавающей точкой Python имеет точность 53 бита, что составляет примерно 16 десятичных цифр. gmpy2 использует точность по умолчанию 53 бита. Если вы хотите получить более точные результаты, вам нужно будет повысить точность.

>>> import gmpy2
>>> from gmpy2 import mpz,mpfr,log2
>>> a=12345678901234567890
>>> gmpy2.get_context().precision=70
>>> mpz(2**log2(a))
mpz(12345678901234567890L)

Чтобы вычислить логарифм по другому, просто используйте

>>> gmpy2.log(x)/gmpy2.log(base)

Обновить

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

Давайте посмотрим на влияние точности. Обратите внимание, что a имеет длину 57 бит, поэтому он не может быть точно представлен с 53 битами с плавающей запятой.

>>> a=123543221556677776
>>> a.bit_length()
57
>>> gmpy2.get_context().precision=53
>>> mpfr(a);2**log2(a)
mpfr('1.2354322155667778e+17')
mpfr('1.2354322155667752e+17')

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

>>> mpfr(a).digits(2);(2**log2(a)).digits(2)
('11011011011101001111001111100101101001011000011001001', 57, 53)
('11011011011101001111001111100101101001011000010111001', 57, 53)

Давайте попробуем увеличить точность до 57 бит.

>>> gmpy2.get_context().precision=57
>>> mpfr(a).digits(2);(2**log2(a)).digits(2)
('110110110111010011110011111001011010010110000110010010000', 57, 57)
('110110110111010011110011111001011010010110000110010011000', 57, 57)

Заметьте, что больше битов верны, но все еще есть ошибка. Давайте попробуем 64 бита.

>>> gmpy2.get_context().precision=64
>>> mpfr(a);2**log2(a)
mpfr('123543221556677776.0',64)
mpfr('123543221556677775.953',64)
>>> mpfr(a).digits(2);(2**log2(a)).digits(2)
('1101101101110100111100111110010110100101100001100100100000000000', 57, 64)
('1101101101110100111100111110010110100101100001100100011111111010', 57, 64)

Большое число конечных 1 примерно равно десятичным в конце.

Как только вы подобрались "достаточно близко", вы можете преобразовать в целое число, которое округлит результат до ожидаемого значения.

Почему не достаточно 57 бит? Библиотека MPFR, используемая gmpy2 выполняет правильное округление. Есть еще небольшая ошибка. Давайте также посмотрим на результаты, используя значения с плавающей запятой непосредственно выше и ниже правильно округленного значения.

>>> gmpy2.get_context().precision=57
>>> b=log2(a)
>>> 2**gmpy2.next_below(b);2**log2(a);2**gmpy2.next_above(b)
mpfr('123543221556677746.0',57)
mpfr('123543221556677784.0',57)
mpfr('123543221556677822.0',57)

Обратите внимание, что даже небольшое изменение b вызывает гораздо большее изменение 2**b,

Обновление 2

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

Я пропустил некоторые детали в следующем - я предполагаю, что все числа между 0 и 1.

С двоичной плавающей точкой (то, что использует большинство компьютеров), знаменатель рационального приближения должен быть степенью 2. Числа как 1/2 или же 1/4 может быть представлен точно. Десятичное число с плавающей запятой использует рациональные аппроксимации со знаменателем, равным десятичной степени. 1/2"1/4", "1/5" и 1/20 все может быть представлено точно. Никто не может представлять 1/3 именно так. Реализация арифметики с плавающей точкой в ​​Base-6 может представлять 1/2 а также 1/3 точно, но не 1/10, Точность определенного формата просто определяет максимальный размер числителя. Всегда будут некоторые рациональные числа, которые не могут быть точно представлены данной базой.

Поскольку иррациональные числа не могут быть записаны как рациональные числа, они не могут быть точно представлены данной базой. Поскольку логарифмические и экспоненциальные функции почти всегда приводят к иррациональным значениям, вычисления почти никогда не бывают точными. Увеличивая точность, вы обычно можете получить "достаточно близко", но вы никогда не сможете получить точную.

Есть программы, которые работают symbolically - они помнят это a является log2(n) и когда вы делаете 2**a, точное значение a возвращается Смотрите SymPy.

Другие вопросы по тегам