Странный результат умножения

В моем коде это умножение в коде C ++ со всеми типами переменных как double []

f1[0] = (f1_rot[0] * xu[0]) + (f1_rot[1] * yu[0]);
f1[1] = (f1_rot[0] * xu[1]) + (f1_rot[1] * yu[1]);
f1[2] = (f1_rot[0] * xu[2]) + (f1_rot[1] * yu[2]);

f2[0] = (f2_rot[0] * xu[0]) + (f2_rot[1] * yu[0]);
f2[1] = (f2_rot[0] * xu[1]) + (f2_rot[1] * yu[1]);
f2[2] = (f2_rot[0] * xu[2]) + (f2_rot[1] * yu[2]);

соответствующие этим значениям

Force Rot1 : -5.39155e-07, -3.66312e-07
Force Rot2 : 4.04383e-07, -1.51852e-08

xu: 0.786857, 0.561981, 0.255018
yu: 0.534605, -0.82715, 0.173264

F1: -6.2007e-07, -4.61782e-16, -2.00963e-07
F2: 3.10073e-07, 2.39816e-07, 1.00494e-07

это умножение, в частности, дает неправильное значение -4,61782e-16 вместо 1,04745e-13

f1[1] = (f1_rot[0] * xu[1]) + (f1_rot[1] * yu[1]);

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

это открытый скомпилированный mpi-код, и приведенный выше результат предназначен для запуска одного процессора; при запуске нескольких процессоров разные значения, например, для 40 процессоров получается 1.66967e-13 в результате умножения F1 [1].

Это какая-то ошибка MPI? или проблема точности типа? и почему это работает хорошо для других умножений?

0

Решение

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

f1[1] = (f1_rot[0] * xu[1]) + (f1_rot[1] * yu[1])
= -3.0299486605499998e-07 + 3.0299497080000003e-07
= 1.0474500005332475e-13

Это то, что мы получаем с числами, которые вы дали в вашем примере.
Заметить, что (-7) - (-13) = 6, что соответствует количеству десятичных знаков в плавающей запятой, которое вы даете в своем примере: (например: -5.39155e-07 -3.66312e-07, каждая мантисса имеет точность 6 десятичных знаков). Это означает, что вы использовали здесь поплавки одинарной точности.

Я уверен, что в ваших расчетах точность ваших чисел выше, поэтому вы найдете более точный результат.

В любом случае, если вы используете поплавки одинарной точности, вы не можете ожидать большей точности. С двойной точностью вы можете найти точность до 16. Вы не должны доверять разнице между двумя числами, если она не больше мантиссы:

  • Простая точность плавает: (a — b) / b> = ~ 1e-7
  • Поплавки двойной точности: (a — b) / b> = ~ 4e-16

Для получения дополнительной информации см. эти примеры … или таблица в этой статье …

5

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector