10^00 и 5.678 * 10^-04:
1.234 * 10^00 + 5.678 * 10^-05 = 1.234 + 0.00005678 = 1.23405678
Это число непредставимо в нашей арифметике и будет заменено ближайшим представимым:
1.234 * 10^00 + 5.678 * 10^-04 = 1.234 * 10^00
Таким образом, при сложении чисел разного порядка результат может быть равен одному из слагаемых. Этот эффект называется потерей значимости.
Рассмотрим более подробно операцию сложения двух положительных чисел. Пусть х > у > 0. Тогда
х + у = х * (1 + у/х)
Если число у/х окажется настолько маленьким, что 1 + у/х = 1, то мы получим потерю значимости: х + у = х.
Машинным эпсилон называется минимальное положительное число, которое при сложении с числом 1.0 дает результат, больший, чем 1.0. Машинное эпсилон - наиболее важная характеристика вещественной арифметики.
В нашей модельной арифметике машинное эпсилон равно 0.001 = 1.000 * 10^-03.
Величину машинного эпсилон можно вычислить как результат выполнения следующей функции:
typedef float real;
real calceps() {
static volatile real eps, eps2, eps21;
eps =1.0;
eps2 = eps * 0.5;
eps21 = eps2 + 1.0;
while( eps21 > 1.0 ) {
eps = eps2;
eps2 = eps * 0.5;
eps21 = eps2 + 1.0;
}
return eps;
}
Заметим, что в этой функции существенно использование переменных eps, eps2 и eps21. Спецификаторы static и volatile использованы для того, чтобы воспрепятствовать возможной оптимизации кода компилятором. Дело в том, что промежуточные вычисления проводятся с использованием 10-байтовых вещественных чисел. По этой же причине условие fabs(x) > calceps() нельзя заменить на следующее условие: 1.0 + fabs(x – y) > 1.0.
Основные параметры машинной арифметики - максимальное представимое число, минимальное положительное число и машинное эпсилон. Максимальное представимое число и минимальное положительное число определяют диапазон чисел, представимых в машинной арифметике, называемый также динамическим диапазоном арифметики. Динамический диапазон определяется разрядностью показателя. Машинное эпсилон определяет точность представления чисел и зависит от разрядности мантиссы.
Несмотря на то, что для всех основных параметров машинной арифметики существуют переносимые способы их вычисления, обычно предпочитают пользоваться готовыми значениями соответствующих констант. Заголовочный файл float.h содержит определения макросов, дающих основные параметры машинной арифметики.
float |
double |
|
максимальное представимое число |
FLT_MAX |
DBL_MAX |
минимальное положительное число |
FLT_MIN |
DBL_MIN |
машинное эпсилон |
FLT_EPSILON |
DBL_EPSILON |
Пусть х - вычисляемое значение, а е - его погрешность. Тривиальная реализация проверки погрешности на малость оператором
fabs (е) < eps
часто приводит к проблемам в случае больших по абсолютной величине значений числа х. Дело в том, что вещественные числа расположены на вещественной оси неравномерно - гуще вблизи нуля и реже вдали (между любыми соседними целыми степенями двойки равномерно расположено одинаковое количество вещественных чисел). Поэтому даже два соседних вещественных числа могут находиться на расстоянии, большем, чем eps. В численных алгоритмах правильная постановка вопроса о малости ошибки звучит так: "является ли погрешность малой по сравнению с ответом". Такая формулировка приводит к следующей реализации:
fabs(e) < eps * fabs(x).
В этой реализации абсолютный порог малости числа зависит от значения величины, с которой она сравнивается - при больших по модулю значениях х даже относительно большие е будут признаны малыми. Действительно, число 1 мало по сравнению с 1е6 в той же степени, что и число 1е-6 по сравнению с 1. Оказывается, что и эта реализация может приводить к проблемам, но уже в случае малых по абсолютной величине чисел х. Если х - почти нуль, то и правая часть получается почти нулевой. В этом случае правая часть может оказаться настолько малой, что никакое е не сможет удовлетворить неравенству. Эту проблему решает такая реализация:
fabs(e) < eps * (1.0 + fabs(x))
Защититься от возможности задания излишне малых значений eps можно следующим образом:
fabs(e) < (eps + 2.0 * FLT_EPSILON) * (1.0 + fabs(x))
Самым важным соображением здесь является следующее: в большинстве случаев следует формулировать численные алгоритмы таким образом, чтобы они содержали только относительные проверки на малость. Наиболее часто такая проверка встречается в следующей ситуации:
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.