2015-10-10 5 views
0

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

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

ответ

1

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

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

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

>>> 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-х символов примерно эквивалентно завершению 9-го числа в десятичной системе.

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

Почему не хватает 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, могут быть представлены точно. Десятичная плавающая точка использует рациональные аппроксимации, которые имеют знаменатель, который является степенью 10. Номера, такие как 1/2, '1/4', '1/5' и 1/20, могут быть представлены точно. Точно также не может быть 1/3. Реализация арифметики с плавающей запятой в базовом варианте 6 может представлять 1/2 и 1/3 точно, но не 1/10. Точность конкретного формата просто определяет максимальный размер числителя. Всегда найдутся некоторые рациональные числа, которые не могут быть точно представлены данной базой.

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

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

+0

Я повысил точность до 100, но выход не работает, если я не использую предоставленный вами код. Пример log2 (123543221556677776) заканчивается с mpfr ('56 .777793469605039610459389190493 ', 100), если я попытаюсь использовать этот вывод, он не соответствует оригиналу. Используя свой код с тем же номером, он работает. Точность должна соответствовать точному количеству бит, необходимых для решения уравнения? –

+0

Я не понимаю, что вы «используете этот вывод». Можете ли вы показать точные команды, которые вы пытаетесь сделать? – casevh

+0

Log2 (x), я копирую и вставляю вывод в mpz (mpfr (2) ** mpfr (y)). x - это число, превышающее 16 цифр, и y - это то, что я копирую и вставляю из вывода. Я пытаюсь использовать это для математической домашней работы, где я могу просто использовать вывод из log2(), чтобы быть правильным. Кажется, что это правильно в памяти не на выходе в интерпретаторе python. –

 Смежные вопросы

  • Нет связанных вопросов^_^