Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лаб_1_метод_указания прога.doc
Скачиваний:
3
Добавлен:
03.11.2018
Размер:
301.57 Кб
Скачать

Катастрофическая потеря порядка (ошибка потери порядка)

Ситуация появления «машинного нуля» в ряде случаев приводит к так называемой катастрофической потере порядка. Например, пусть для представления вещественного числа выделено 3 разряда под мантиссу и 2 под порядок. Тогда имеем:

0.425*10-27/0.561*1078*0.200*1087=0.0757575…*10-105*0.200*1087=0.757575…* 10-106*0.200*1087=0, т.к. из предыдущего примера мы знаем, что 0.757575…*10-106 есть 0, то вместо ожидаемого результата, получаем значение 0.1515151*10-19.

Указанные исключительные ситуации нужно отслеживать и специально обрабатывать в программе.

Операции сложения и вычитания

При сложении и вычитании вещественных чисел процессор выполняет следующие действия:

  • выравнивание мантисс, т.е. сдвиг мантиссы числа с меньшим порядком на число разрядов, равное разности порядков

  • вычисляет сумму (разность) мантисс операндов

  • определяет порядок результата как больший из порядков операндов

  • нормализует мантиссу результата, если это необходимо

  • выполняет соответствующую корректировку порядка результата, если это необходимо.

При этом возможно возникновение некоторых особых (исключительных) ситуаций, как последствий действий процессора.

Переполнение (ошибка переполнения)

Из-за ограниченности разрядов под представление мантиссы и порядка числа при выполнении операций сложения и вычитания возможен «выход» значения мантиссы или порядка за разрядную сетку. Например, пусть для представления вещественного числа выделено 3 разряда под мантиссу и 2 под порядок. Тогда при сложении двух чисел 0.999*1098 и 0.976*1099 имеем:

0.999*1098 + 0.976*1099 = 0.099(9)*1099 + 0.976*1099 = 0.100*1099 + 0.976*1099 = 1.076*1099 = 0.108*10100 = 0.108*10** т.к. числа сначала приводятся к одинаковому – большему порядку, затем производится сложение мантисс и после этого повторная нормализация, при которой значение нового порядка 100 выходит за отведенные ему 2 разряда, т.е. имеем ошибку переполнения.

Потеря значащих цифр

При выполнении операций сложения и вычитания вещественных чисел может произойти потеря значащих цифр. Например,

  • 10-9.82 = 0.18 (ожидаем)

10-9.82 = 0.100*1002–0.982*1001 = 0.100*1002–0.0982*1002= 0.100*1002–0.098*1002 = 0.002*1002 = 0.2 (получаем, если проводилось усечение).

  • 1000 – 999 = 1 (ожидаем)

1000 – 999 = 0.100*1004 – 0.999*1003 = 0.100*1004 – 0.0999*1004 = 0.100*1004 – 0.100*1004=0 (получаем, если проводилось округление) или 1000 – 999 = 0.100*1004 – 0.999*1003 = 0.100*1004 – 0.0999*1004 = 0.100*1004 – 0.099*1004=0.001*1004 =10 (вместо ожидаемой 1, если проводилось усечение).

Как следствие из всего сказанного: при выполнении арифметических операций сложения и вычитания над вещественными числами возможны «особые» случаи, нарушающие привычную логику организации вычислений. Рассмотрим два возможных случая.

Пример 1. Вычисление y(x) = (1-cos x) / x2. Эта формула не работает для малых значений х (уменьшаемое равно 1, вычитаемое стремится к 1, все делится на малое число). Для получения правильных результатов формулу необходимо преобразовать к виду z(x) = 2 sin2 (x/2) / x 2.

Пример 2. Не всегда выполняется и ассоциативный закон сложения. При сложении одинаковых чисел с разными знаками происходит потеря значимости. Проанализируйте примеры:

float x, y, z, r, v; x=1.1e22; y = -1.1e22; z= 1.0e2; r= (x+y)+z; cout<<r<<endl; //напечатает 100, т.к. //(1.1e22 + -1.1e22) + 1.0e2 = 0.0e22 + 1.0e2 = 100 r= x+(y+z); cout << r <<endl; //напечатает 0, т.к. //1.1e22 + (-1.1e22 + 1.0e2) = 1.1e22 + (-1.1e22) = 0 v= x+y; r= v+z; cout << r <<endl; //напечатает 100, т.к. //(1.1e22 + -1.1e22 )+ 1.0e2 = 0.0e22 + 1.0e2 = 100 v= y+z; r= x+v; cout << r << endl; //напечатает 0, т.к. //1.1e22 + (-1.1e22 + 1.0e2) = 1.1e22 + (-1.1e22) = 0