2015-03-30 3 views
0

Следующий простой код:Неточности с десятичными знаками в Python

from decimal import getcontext 
from decimal import * 
import math 

context = getcontext() 
context.prec = 300  

def f(x): 
    return Decimal(math.atan(10**(-x+1))) 

def xNext(x,y): 
    return x-y*f(2) 


def yNext(x,y): 
    return y+x*f(2) 

x= Decimal(1) 
y = Decimal(0) 

x=xNext(x,y) 
y=yNext(x,y) 

x=xNext(x,y) 
y=yNext(x,y) 

x=xNext(x,y) 
y=yNext(x,y) 

print("{:.16f}".format(x)) 
print("{:.16f}".format(y)) 

возвращает

0.9702971603146833 
0.2950554229911823 

Что неправильно, должно быть около 0,97019857 и 0,2980158649 я думал, что это была ошибка округления, но этот код должен работать до 300 знаков после запятой.

Не уверен, что если другая проблема или на самом деле не собирается 300 мест ...

EDIT: Да, я сомневаюсь, что это ошибка округления, я только что сделал тот же самый процесс на вольфрам только около 20 знаков после запятой в то время, и мой ответ более точен, чем этот.

+0

Я просто попытался выполнить фрагмент кода, но он не работает для меня. Сообщение об ошибке «ValueError: имя поля нулевой длины в формате» в предыдущей строке. Выполнение с помощью Ipython и Python 2.6.8 ... – WWhisperer

+0

@WWhisperer добавить '0'' {0: .16f} 'к вашему форматированию –

+0

@WWhisperer: для этого формата печати требуется Python 2.7 или выше. Но Padraic показывает, как сделать его совместимым с Python 2.6 и более поздними версиями. –

ответ

2

Десятичный размер не увеличивает вашу точность, потому что вы используете модуль math. Но дело не в этом. Вы уверены, что расчет правильный? Только что попробовал:

x, y = 1, 0 
x, y = xNext(x,y), yNext(x,y) 
x, y = xNext(x,y), yNext(x,y) 
x, y = xNext(x,y), yNext(x,y) 

И это приводит к

0.970198479132 
0.298015864998 

, которая в основном ваш ожидаемый результат.

+0

Эй, это!Извините, но я работаю в основном вручную. Любая идея, почему это работает, когда мой нет? Они выглядят функционально одинаково для меня ... – user2998454

+2

Версия от @Daniel вычисляет xNext и yNext, используя те же значения x и y, а затем обновляет обе переменные одновременно. В вашем коде yNext рассчитывается из обновленной версии x, а не оригинала x. – casevh

+0

@ user2998454: FWIW, используя mpmath по этому алгоритму, я получаю 0.970198479131787944181898676847 & 0.298015864997778768581294686561; требовалось только 30 цифр точности ('mp.dps = 30'), более высокие настройки точности здесь не имеют значения. –

1

Я думаю, что проблема лежит здесь:

return Decimal(math.atan(10**(-x+1))) 

Я предположил бы, что все расчеты в этой формуле (особенно math.atan функции) будет рассчитываться как обычные точности с плавающей запятой - и затем преобразуется обратно в десятичную десятичную точку с десятичной точкой.

Если вы хотите точность в 300 точек, вы ДОЛЖНЫ найти способ гарантировать, что каждый расчет будет выполнен с таким уровнем точности или лучше, так как ваш результат будет только таким точным, как ваш точный расчет LEAST.

+1

Но мой калькулятор (CAS) делает это только с 16 знаками после запятой, также моя ошибка составляет только около 3-го или четвертых десятичных разрядов, и у меня были более сложные функции с более квадратными корнями, и итерации работают с гораздо большей точностью. – user2998454

+0

Как сказал Даниэль, у вас были функциональные проблемы в вашем коде, но мой основной момент остается в силе - вы не можете выполнять вычисления с 16-ти десятичной точкой, а затем неожиданно ожидать результат с точностью до 300 знаков после запятой - если все ваши значения в лучшем случае равны 16 пунктам, а в лучшем случае - 16 пунктов, тогда самый точный результат будет 15 пунктов. Невозможно внезапно создать другие 285 десятичных точек информации, если их уже нет. –

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