Компьютерная точность: когда мне следует об этом беспокоиться?

В программировании на 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?

Мои вопросы:

  1. Могут ли быть небольшие помехи в работе с double введите цифры?
  2. Что может вызвать такие мелкие нарушения? т.е. ошибки округления становятся большими? Не могли бы вы перечислить их? Как принять меры предосторожности?
  3. Если в определенных операциях могут быть небольшие помехи, значит ли это после этих операций, используя if (SUM == 0) опасно? Нужно всегда использовать if (SUM < SMALL) вместо этого, где SMALL определяется как очень небольшое значение, такое как 1E-30?
  4. Наконец, могут ли небольшие помехи привести к отрицательному значению? Потому что если это возможно, то мне лучше использовать if (abs(SUM) < SMALL) вместо.

Есть опыт?

2 ответа

Решение

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

Одна из наиболее важных частей - катастрофическая отмена

Катастрофическая отмена происходит, когда операнды подвержены ошибкам округления. Например, в квадратной формуле встречается выражение b2 - 4ac. Величины b2 и 4ac подвержены ошибкам округления, поскольку они являются результатом умножения с плавающей точкой. Предположим, что они округлены до ближайшего числа с плавающей запятой и поэтому с точностью до.5 ulp. Когда они вычитаются, отмена может привести к исчезновению многих точных цифр, оставляя в основном цифры, загрязненные ошибкой округления. Следовательно, разница может иметь ошибку многих ульпов. Например, рассмотрим b = 3.34, a = 1.22 и c = 2.28. Точное значение b2 - 4ac составляет 0,0292. Но b2 округляет до 11,2 и 4ac округляет до 11,1, следовательно, окончательный ответ равен 0,1, что является ошибкой на 70 ульпов, хотя 11,2 - 11,1 точно равно 0,16. Вычитание не внесло никакой ошибки, но выявило ошибку, внесенную в более ранние умножения.

Доброкачественная отмена происходит при вычитании точно известных количеств. Если x и y не имеют ошибки округления, то по теореме 2, если вычитание выполняется с защитной цифрой, разность xy имеет очень небольшую относительную ошибку (менее 2).

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

Для вашего конкретного примера 0 имеет точное представление в виде двойного числа, и добавление ровно 0 к двойному не меняет его значения.

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

Чтобы получить лучшее представление о "помехах", мне нужно знать, какие вычисления выполняет ваш код.

Другие вопросы по тегам