На изображении выше показана галактика из моделирования, созданного Исследовательской группой Хопкинса в Калифорнийском технологическом институте. Подобные симуляции являются важной частью современной астрономии и могут потребовать огромных вычислительных мощностей. Они также могут потребовать использования высокоточной арифметики для получения значимых результатов. Например, в одном исследовании нашей Солнечной системы, которое было рассчитано с использованием арифметики с двойной точностью, было установлено, что вычисленный угол имел ошибку более 1 радиана из-за округления!
В этой краткой статье рассматривается причина № 1, по которой в числовых расчетах теряется точность: что это такое и что с этим делать.
Давайте начнем с довольно простого примера, взятого из научной литературы (см. ссылку в конце этой статьи). Я буду использовать для этого Julia, но используемые принципы применимы к высокоточным вычислениям на любом языке. Мы хотим вычислить значение
На первый взгляд это выглядит достаточно просто. Просто запустите Julia и введите выражения:
julia> a = sin(10^22); julia> b = log(17.1); julia> c = exp(0.42); julia> 173746a + 94228b - 78487c 2.9103830456733704e-11
У нас есть ответ, и Джулия не жаловалась. Проблема в том, что полученный нами ответ не очень близок к правильному значению -1,3418189578e-12! Что случилось? Давайте посмотрим на отдельные термины в нашем выражении.
julia> t1 = 173746a julia> t2 = 94228b julia> t3 = 78487c julia> println("t1 = $t1, t2 = $t2, t3 = $t3") t1 = -148066.48884364998, t2 = 267520.6854594897, t3 = 119454.1966158397 julia> println("t1+t2 = $(t1+t2)") t1+t2 = 119454.19661583973
Обратите внимание, что t1+t2 очень близко к значению t3. Это приводит к известной проблеме численных вычислений, которая может привести к большим потерям точности. Когда вычитаются два числа, очень близкие друг к другу, общие цифры фактически сокращаются, и только оставшиеся цифры остаются значимыми. Легче всего это увидеть, если делать вычитание так, как это делали в школе, выстраивая цифры:
В этом примере при вычитании двух чисел остается только одна цифра точности, что фактически делает расчет недействительным.
Итак, что вы можете сделать по этому поводу? В некоторых случаях вы можете перестроить вычисление терминов, чтобы избежать подобных вычитаний. Однако, если это невозможно, вы обычно можете использовать высокоточную арифметику и увеличить точность значений до точки, при которой достигается достаточная точность. Вот тот же расчет, но выполненный со значениями BigFloat, чтобы получить лучший результат:
julia> abig = sin(BigFloat("1.0e22")); julia> bbig = log(BigFloat("17.1")); julia> cbig = exp(BigFloat("0.42")); julia> coeffa = BigFloat("173746"); julia> coeffb = BigFloat("94228"); julia> coeffc = BigFloat("78487"); julia> coeffa*abig + coeffb*bbig - coeffc*cbig -1.341818957829619549704278684230958880945236623213976217962437160120011379004573e-12
Ссылка «Почему и как использовать произвольную точность» Гази и др. al., Вычисления в науке и технике, Vol. 12, выпуск 3, май-июнь 2010 г.