суббота, 29 августа 2015 г.

Ошибки численных приближений

Компьютер, в отличие от "чистой" математики, оперирует не правильными числами, но их приближениями, точность которых технически ограничена. В абсолютном большинстве случаев погрешность ничтожна.
В этом постике - два случая из одной и той же строчки кода, когда она оказалась принципиальной. 
Наверное, эту строчку следует использовать в целях карательной педагогики.

Случай первый. От перемены мест слагаемых сумма меняется.


Дано:
Есть массив oxmass_sum, каждый элемент которого определяется по формуле, приведённой на картинке: oxmass_sum(i) = oxmass_sum(i) + tmass*foxide(i) - mass_oxide_new(i).

Источник проблемы и к чему это приводит:
Значения массива oxmass_sum(:) могут быть порядка единицы и её десятых долей. С другой стороны, количество знаков tmass*foxide(i) превышает точность вычислений. Поэтому при вычислении при прибавлении к oxmass_sum(i) величины tmass*foxide(i) и выполнении дальнейших операций величина отбрасывается.

Решение:
Переставить oxmass_sum(i) в конец суммы:
oxmass_sum(i) = tmass*foxide(i) - mass_oxide_new(i) + oxmass_sum(i)

Комментарий:
Об этом меня предупреждали книжки 60-х годов. Однако их рекомендация была в суммах упорядочивать числа по возрастанию - и в данном случае она таки не срабатывает. Складывать надо после приведения к единому порядку величины.
Подход к пределу точности явно следует из спецификации типа данных REAL*8.

PS: да, я глупый, порядок столбцов в третьей таблице
tmass, foxide(:), mass_oxide_new(:), oxmass_sum(:)_old, oxmass_sum(:)_new

Случай второй. Разница в адцатом знаке.


Дано:
Есть массив oxmass_sum, каждый элемент которого определяется по формуле, приведённой на картинке: oxmass_sum(i) = tmass*foxide(i) - mass_oxide_new(i) + oxmass_sum(i).

Источник проблемы: 
Для расчёта массива mass_oxide_new(i) есть два массива cox(:) и cc(:), причём cc(:) - это изначальные значения, а cox(:) - те же, но полученные из другого источника (при этом они должны быть равны, т.к. считаются из одних и тех же констант, только по разным формулам). Как можно увидеть в строке вывода, представление чисел несколько отличается - хотя с точностью до энного знака числа полностью идентичны.

К чему это приводит:
При перемножении этих одних и тех же с машинной точностью (VARIANT 1) на скриншоте на константу tmass полученное третье значение массива cox отличается на 0.5 от cc(3)*tmass и foxide(3)*tmass. Как результат, массив с разностями получается ненулевой. 
Несмотря на то, что полученная разность на много порядков меньше исходных величин, в дальнейшем расчёте она принципиальна: там уже идёт игра в малые числа.

Решение:
Физически приравнивать числа, если их разность меньше определённого предела. Массив получается нулевой.

Комментарий:
В принципе, просто иной поворот старого правила, что сравнивать два числа с плавающей точкой (if a == b then ...) некорректно и неправильно. Однако здесь домножение на Очень Большое Число tmass привело к тому, что исчезающая разность стала вполне расчётной величиной.



PS: а меня шеф похвалил! "It's great that you are finding some subtle bugs." уруру

Комментариев нет:

Отправить комментарий