#python-3.x #numpy #numerical-methods #numerical-analysis
#python-3.x #numpy #числовые методы #числовой анализ
Вопрос:
Я выполняю некоторое упражнение по числовому анализу, в котором мне нужно рассчитать решение линейной системы с использованием определенного алгоритма. Мой ответ отличается от ответа книги на несколько десятичных знаков, что, как я полагаю, связано с ошибками округления. Есть ли способ, с помощью которого я могу автоматически устанавливать арифметику на округление до восьми знаков после запятой после каждой арифметической операции? Ниже приведен мой код на python.
import numpy as np
A1 = [4, -1, 0, 0, -1, 4, -1, 0,
0, -1, 4, -1, 0, 0, -1, 4]
A1 = np.array(A1).reshape([4,4])
I = -np.identity(4)
O = np.zeros([4,4])
A = np.block([[A1, I, O, O],
[I, A1, I, O],
[O, I, A1, I],
[O, O, I, A1]])
b = np.array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6])
def conj_solve(A, b, pre=False):
n = len(A)
C = np.identity(n)
if pre == True:
for i in range(n):
C[i, i] = np.sqrt(A[i, i])
Ci = np.linalg.inv(C)
Ct = np.transpose(Ci)
x = np.zeros(n)
r = b - np.matmul(A, x)
w = np.matmul(Ci, r)
v = np.matmul(Ct, w)
alpha = np.dot(w, w)
for i in range(MAX_ITER):
if np.linalg.norm(v, np.infty) < TOL:
print(i 1, "steps")
print(x)
print(r)
return
u = np.matmul(A, v)
t = alpha/np.dot(v, u)
x = x t*v
r = r - t*u
w = np.matmul(Ci, r)
beta = np.dot(w, w)
if np.abs(beta) < TOL:
if np.linalg.norm(r, np.infty) < TOL:
print(i 1, "steps")
print(x)
print(r)
return
s = beta/alpha
v = np.matmul(Ct, w) s*v
alpha = beta
print("Max iteration exceeded")
return x
MAX_ITER = 1000
TOL = 0.05
sol = conj_solve(A, b, pre=True)
Используя это, я получаю 2.55516527 в качестве первого элемента массива, который должен быть 2.55613420.
ИЛИ, есть ли язык / программа, где я могу указать точность арифметики?
Комментарии:
1. Я получаю
2.55516527
2. @dawg Извините, похоже, я тоже получаю 2.55516527. Похоже, что я использовал другое значение для TOL.
3. Убедитесь, что вы понимаете разницу между округлением фактических значений и округлением при отображении значений.
4. @SantoshLinkha Округление после КАЖДОЙ операции сильно искажает ваши данные.
5. Округление до восьми десятичных знаков после каждой операции — верный способ ухудшить точность !
Ответ №1:
Точность / округление во время вычисления вряд ли будет проблемой.
Чтобы проверить это, я выполнил вычисление с точностью, заключающей в скобки точность, к которой вы стремитесь: один раз с np.float64
, и один раз с np.float32
. Вот таблица напечатанных результатов, их приблизительная десятичная точность и результат вычисления (т.Е. Первое напечатанное значение массива).
numpy type decimal places result
-------------------------------------------------
np.float64 15 2.55516527
np.float32 6 2.5551653
Учитывая, что они настолько согласуются, я сомневаюсь, что промежуточная точность в 8 знаков после запятой даст ответ, который не находится между этими двумя результатами (т. 2.55613420
Е. отключен в 4-й цифре).
Это не часть, не часть моего ответа, а комментарий к использованию mpmath
. Спрашивающий предложил это в комментариях, и это была и моя первая мысль, поэтому я провел быстрый тест, чтобы проверить, работает ли он так, как я ожидал, при вычислениях с низкой точностью. Этого не произошло, поэтому я отказался от него (но я не эксперт в этом).
Вот моя тестовая функция, в основном умножающаяся 1/N
на N
и 1/N
повторно, чтобы подчеркнуть ошибку 1/N
.
def precision_test(dps=100, N=19, t=mpmath.mpf):
with mpmath.workdps(dps):
x = t(1)/t(N)
print(x)
y = x
for i in range(10000):
y *= x
y *= N
print(y)
Это работает, как и ожидалось, например, np.float32
:
precision_test(dps=2, N=3, t=np.float32)
# 0.33333334
# 0.3334327041164994
Обратите внимание, что ошибка распространилась на более значащие цифры, как и ожидалось.
Но mpmath
я никогда не мог добиться этого (тестирование с диапазоном dps
и различными простыми N
значениями):
precision_test(dps=2, N=3)
# 0.33
# 0.33
Из-за этого теста я решил mpmath
, что он не даст нормальных результатов для вычислений с низкой точностью.
TL; DR:
mpmath
не вел себя так, как я ожидал, с низкой точностью, поэтому я отказался от него.
Комментарии:
1. Я не знаю, что делать. Я также думал о работе с одинарной точностью, однако это не сработало. Вот ссылка на ответ. imgur.com/yAdVzQ3
2. Вы уверены, что об этом стоит беспокоиться? В книгах часто встречаются опечатки, и все время возникают небольшие ошибки, и вы также находитесь в пределах «остаточного» и «допуска». Например, небольшая ошибка в начальном условии или искажение условия остановки могут привести к очень легкому возникновению ошибок такого типа.
3. Я почти уверен, что я правильно реализовал алгоритм. imgur.com/xHjDBJD Полагаю, мне придется сдаться. Также все мы изначально начинаем с x = 0.
4. @SantoshLinkha: Я немного посмотрел на это, и единственное, чего я не совсем понимаю, это определение D и $ C ^ {-1} $ в постановке задачи. Похоже, что точное определение $ C ^ {-1} $ — это то, что может привести к небольшим отклонениям, которые вы видите, что также интересно, потому что это то, что мне наименее понятно. Я бы посоветовал внимательно изучить это (т. Е. Ваш расчет Ci) и, возможно, попробовать несколько вариантов или других способов интерпретации терминов, если вы знаете разумные.
5. C = sqrt диагональных элементов.