В программировании на C ++, когда мне нужно беспокоиться о точности? Чтобы взять небольшой пример (хотя, возможно, он не идеален),
std::vector<double> first (50000, 0.0);
std::vector<double> second (first);
Возможно ли, что second[619] = 0.00000000000000000000000000001234
(Я имею ввиду очень маленькое значение). Или же SUM = second[0]+second[1]+...+second[49999] => 1e-31
? Или же SUM = second[0]-second[1]-...-second[49999] => -7.987654321e-12
?
Мои вопросы:
double
введите цифры?if (SUM == 0)
является опасно? Нужно всегда использовать if (SUM < SMALL)
вместо этого, где SMALL
определяется как очень небольшое значение, такое как 1E-30
?if (abs(SUM) < SMALL)
вместо.Есть опыт?
Это хороший справочный документ для точности с плавающей запятой: Что каждый компьютерщик должен знать об арифметике с плавающей точкой
Одна из наиболее важных частей — катастрофическая отмена
Катастрофическая отмена происходит, когда операнды
ошибки округления. Например, в квадратной формуле выражение
b2 — 4ac происходит. Величины b2 и 4ac подлежат округлению
ошибки, так как они являются результатом умножения с плавающей точкой.
Предположим, что они округлены до ближайшего числа с плавающей точкой,
и так с точностью до .5 ulp. Когда они вычитаются,
отмена может привести к исчезновению многих точных цифр,
оставляя в основном цифры, загрязненные ошибкой округления. Следовательно
Разница может иметь ошибку многих ульпов. Например, рассмотрим b =
3,34, а = 1,22 и с = 2,28. Точное значение b2 — 4ac составляет 0,0292. Но b2 округляет до 11,2 и 4ac округляет до 11,1, следовательно, окончательный ответ
равно .1, что является ошибкой на 70 ульпов, хотя 11.2 — 11.1 точно
равно .16. Вычитание не внесло никакой ошибки, а скорее
выявил ошибку, внесенную в более ранние умножения.Доброкачественная отмена происходит при вычитании точно известных количеств.
Если x и y не имеют ошибки округления, то по теореме 2, если
вычитание делается с защитной цифрой, разница х-у очень
небольшая относительная погрешность (менее 2).Формула, которая проявляет катастрофическую отмену, иногда может быть
переставил для устранения проблемы. Опять рассмотрим квадратичный
формула
Для вашего конкретного примера 0 имеет точное представление в виде двойного числа, и добавление ровно 0 к двойному не меняет его значения.
Кроме того, как и любые другие значения, которые вы помещаете в переменные, числа, которые вы инициализируете в массиве, не будут загадочно изменяться. Вы получаете округление только тогда, когда результат вычисления не может быть точно представлен как число с плавающей запятой.
Чтобы получить лучшее представление о «помехах», мне нужно знать, какие вычисления выполняет ваш код.