Bigfloat - Ошибка в точности
Я пытаюсь использовать библиотеку Bigfloat в Python 2.7.
from bigfloat import *
f1 = Context(precision=2000)
with precision(2000): f1 = 1e-19*1e-19*9e9/((1-1e-18)*(1-1e-18))-1e-19*1e-19*9e9
with precision(100): f2 = 1.6e-27*1.6e-27*6.6e-11/(1e-18*1e-18)
print BigFloat(f1) print f2
Python дает мне f1=0
, но это не так. Я проверил это с g++, и результат 1.75e-46
,
Это ошибка в моей программе? Разве нельзя рассчитать эту точность с Bigfloat? Это ошибка в библиотеке?
1 ответ
В качестве примера, вот как вы можете вычислить f1
с точностью до 256 бит, используя bigfloat
библиотека.
>>> from bigfloat import BigFloat, precision
>>> with precision(256):
... x = BigFloat('1e-19')
... y = BigFloat('9e9')
... z = BigFloat('1e-18')
... f1 = x * x * y / ((1 - z) * (1 - z)) - x * x * y
...
>>> f1
BigFloat.exact('1.800000000000000002700000000000000003600000000000000004500006811997284879750608e-46', precision=256)
Обратите внимание на использование BigFloat('1e-19')
, который создает ближайший двоичный файл с плавающей точкой 10**-19
с текущей точностью (256 бит). Это отличается от BigFloat(1e-19)
(без одинарных кавычек), так как есть 1e-19
это число с плавающей точкой Python, поэтому оно уже округлено до 53-битной точности.
Посмотрите на документацию для более подробной информации.
Однако, с небольшим творческим потенциалом и алгеброй, вам не нужна высокоточная библиотека. Вы можете переписать выражение для f1
как:
f1 = x * x * y * (1 / ((1 - z) * (1 - z)) - 1)
и поместив все в общий знаменатель, количество в скобках можно переписать как (2 - z) * z / ((1 - z) * (1 - z))
, Таким образом, вы могли бы одинаково хорошо вычислить f1
как:
f1 = x * x * y * (2-z) * z / ((1 - z) * (1 - z))
и в этой форме вы не теряете точность, когда z
очень маленький Так что теперь обычные поплавки Python достаточно хороши:
>>> x = 1e-19
>>> y = 9e9
>>> z = 1e-18
>>> f1 = x * x * y * (2 - z) * z / ((1 - z) * (1 - z))
>>> f1
1.8e-46
Если вы решите, что хотите использовать высокоточную библиотеку с плавающей точкой, я бы также порекомендовал взглянуть на библиотеку gmpy2. Он основан на той же базовой библиотеке MPFR, что и bigfloat, но лучше поддерживается.