Точные коэффициенты Рунге-Кутты - PullRequest
0 голосов
/ 11 сентября 2018

При использовании численных методов (например, Рунге-Кутта ) конечная точность операций на компьютере может повлиять на решение (закон Брауэра).

В этой статье предлагается в качестве средства, имитирующего точные коэффициенты Рунге-Кутты, например, A = B + C, где B - точный номер машины, а C - небольшая поправка

Может кто-нибудь объяснить, как это работает на практике? Например. если A = 3/10, то как определить B и C?

Спасибо за любую помощь.

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Этот трюк мог сработать в 2007 году, когда был представлен документ, но я думаю, что он вряд ли будет работать на современной платформе.

На современном процессоре x86 (32- и 64-разрядном) есть два отдельных набора команд для вычислений с плавающей запятой:

  • более старые инструкции x87 (начиная с оригинального сопроцессора 8087), которые имели 80-битные регистры

  • более свежие инструкции SSE, в которых используются регистры той же ширины, что и формат (32 бита для float, 64 бита для double).

Новые инструкции SSE обычно предпочитаются современными компиляторами, так как они, как правило, быстрее, так как они могут быть полностью конвейерными и поддерживают такие интересные вещи, как операции SIMD. Однако в 2007 году некоторые компиляторы по-прежнему использовали только инструкции x87 по умолчанию, поскольку двоичные файлы можно было использовать на старых машинах (это было особенно актуально на 32-разрядных машинах).

80-битные регистры поддерживали значение до 64 бит, что на 11 бит больше, чем 53-битное значение и 64-бит double. Идея состоит в том, что вы могли бы потенциально уменьшить промежуточную ошибку округления, которую в этом случае вы могли бы использовать.

Рассмотрим более простую версию их задачи: вычисления

Y = A*X

путем разбиения A на B+C, как они предполагают, B имеет только 10 значащих бит. Тогда операция

B*X

не вызывает ошибок округления, так как в нем будет не более 63 значащих бит. Полный расчет

Y = B*X + C*X
Таким образом,

даст вам результат с почти полными 64 битами точности.

Без расширенной точности B*X будет обычно вызывать ошибку округления примерно того же размера, как если бы вы только что вычислили A*X напрямую (если только X не был сохранен с уменьшенной точностью).

Теперь это звучит замечательно: вы можете задаться вопросом, почему инструкции SSE избавились от этого? К сожалению, это не было предсказуемо: в некоторых случаях компилятор устроил бы это так, чтобы это работало, но в других случаях ему нужно будет «пролить» регистры в память, и в этом случае вы потеряете эту дополнительную точность. Это, в свою очередь, дает иногда странные результаты, например, когда такие операции, как x+y == x+y, оцениваются как ложные, в зависимости от того, когда были оценены отдельные операции.

Однако еще не все потеряно! Если у вас достаточно свежая машина, вы можете воспользоваться преимуществами операций плавное умножение-сложение (fma) , чтобы повысить точность. В этом случае это будет выглядеть примерно так:

Y = fma(B,X,C*X)
0 голосов
/ 11 сентября 2018

В статье они предлагают использовать рациональное приближение для A со знаменателем 1024. (Это означает, что A имеет не более 10 значащих ненулевых битов).У вас есть (3/10) * 1024 = 307,2, поэтому B будет

B = 307/1024 = 0,2998046875, а C = A - B = 0,0001953125

C не совсем точно представляется как IEEE.Binary64, ближайшее число с плавающей запятой будет

C = 1.9531249999998889776975374843 ... E-4.

Вставьте эти значения в формулы (3.1f)

...