Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Lab_1_2

.pdf
Скачиваний:
16
Добавлен:
18.03.2015
Размер:
728.83 Кб
Скачать

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

бункер заполнился до 300 кг.

Что произойдет после её включения?

Фасовочная машина может забрать из бункера 100 кг продукции, а вес продукции в бункере не изменится, потому что мантиссы чисел 300 и 0,00001 не пересекаются для формата float.

Далее формовочная машина доведет вес бункера до 500 кг и остановится.

Фасовочная машина заберет все таблетки из бункера и тоже остановится. Программа будет показывать вес в бункере 500кг.

Пример программного кода, реализующего данную задачу:

void farmaSimulation()

{

float bunker, bufBunker, bunker1, tablet, tablet1, compens, bufBadBunker, badBunker;

long int n, i;

tablet = 0.00001;

// вес таблетки

tablet1 = 0.0;

// вес таблетки с учетом ошибки в предыдущих

итерациях

 

bunker = 300.0; // исходный вес бункера

bunker1 = 0.0;

// вес бункера после очередной итерации

compens = 0.0;

// компенсация веса таблетки

bunker = 300.0; // исходный вес бункера

bunker1 = 0.0;

// вес бункера после очередной итерации

badBunker = bunker; bufBunker = bunker; bufBadBunker = bunker;

n = 10000000;

// количество циклов

printf("Source bunker capasity = %04.5f kg\n", bunker); for (i = 0; i < n; i++)

{

//вес таблетки с компенсацией ошибки tablet1 = tablet - compens;

//вес бункера после вычета скомпенсированной таблетки bunker1 = bunker - tablet1;

//вычисление компенсации для следующей итерации compens = (bunker - bunker1) - tablet1;

//новый вес бункера

bunker = bunker - tablet1;

// второй бункер не учитывает поправки на суммирование

 

11

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

badBunker -= tablet;

}

printf("Final bunker capasity = %04.5f kg\n", bunker);

printf("Out = %04.5f kg \t diff = %04.5f kg\n\n", tablet*n, bufBunker - bunker);

printf("Final bad bunker capasity = %04.5f kg\n", badBunker);

printf("Out = %04.5f kg \t diff = %04.5f kg\n", tablet*n, bufBadBunker - badBunker);

}

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

Нужно обратить особое внимание, что может не выполняться, например, закон алгебраической коммутативности при вычислениях в формате IEEE754. Например, (a + b) + с = (a + c) + b, обычно не выполняется при вычислениях.

Например, (1020+1)-1020=0 ≠ (1020-1020)+1=1.

Непредставимые в машинной арифметике числа оказываются заданными приближенно, и точность приближения зависит от того, какая используется арифметика — одинарной или двойной точности. Кроме этого следует помнить, что все промежуточные вычисления происходят в арифметике расширенной точности.

Поэтому в следующем примере

float x4 = 0.1;

double x8 = 0.1;

не стоит полагать, что x4 == 0.1 или x8 == 0.1. Дело в том, что при сравнении используется 10-байтовое представление для константы 0.1, не совпадающее с 8-

байтовым в случае переменной x8 и 4-байтовым для x4. Ясно, что по аналогичной причине не будет выполнено равенство x4 == x8.

Последовательные операции с непредставимыми числами могут приводить к накоплению погрешности. Например, если просуммировать 1000 4-байтовых представлений (float) числа 0.1, то мы получим результат, отличающийся на

0.000953674 от точного. Это — вполне заметная погрешность. 12

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

Просуммируем вещественные числа вида 1.0/j при j = 1...1000 в разном порядке

— по возрастанию и по убыванию. При использовании вещественной арифметики однократной точности (float) полученные результаты будут отличаться на 6.67572e006.

Потеря значимости

Для построения примеров удобно использовать следующую модельную арифметику. Пусть используется десятичная система счисления, мантисса имеет 4

десятичных разряда, а показатель — 2 десятичных разряда. Одно из вещественных чисел, представимых в такой арифметике: 9.876e-12. Подобных вещественных чисел имеется лишь конечное число. Рассмотрим операцию сложения чисел 1.234e00 и 5.678e-04 в арифметике, имеющей

1.234e00 + 5.678e-05 = 1.234 + 0.00005678 = 1.23405678

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

1.234e00 + 5.678e-05 = 1.234e00

Таким образом, при сложении чисел разного порядка результат может быть равен одному из слагаемых. Этот эффект называется потерей значимости.

Машинное эпсилон

Рассмотрим операцию сложения двух положительных чисел. Пусть x > y > 0.

Тогда

x + y = x (1 + y/x)

Если число y/x окажется настолько маленьким, что 1 + y/x = 1, то получим потерю значимости: x + y = x.

Машинным эпсилон называется минимальное положительное число, которое при сложении с числом 1.0 дает результат, больший, чем 1.0.

Машинное эпсилон — наиболее важная характеристика вещественной арифметики.

Максимальное представимое число и минимальное положительное число определяют диапазон чисел, представимых в машинной арифметике, называемый также динамическим диапазоном арифметики. Динамический диапазон определяется

13

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

разрядностью показателя. Машинное эпсилон определяет точность представления чисел и зависит от разрядности мантиссы.

Заголовочный файл float.h содержит определения макросов, дающих основные параметры машинной арифметики.

 

float

double

максимальное представимое число

FLT_MAX

DBL_MAX

минимальное положительное число FLT_MIN

DBL_MIN

машинное эпсилон

FLT_EPSILON DBL_EPSILON

Проверка числа на малость

При работе с числами в формате float часто возникает ошибка при проверке на равенство. Например,

float fValue = 0.2; if (fValue == 0.2)

{

//…

}

0,2 – не имеет точного двоичного представления.

0,2 – это константа двойной точности, а переменная fValue – одинарной, и

никакой гарантии о поведении этого сравнения нет.

Лучше сравнивать разницу с допустимой абсолютной погрешностью:

if (fabs(fValue – fExpected) < 0.0001)

{

//…

}

Недостаток такого метода в том, что погрешность представления числа увеличивается с ростом самого этого числа. Если fValue = 10000, то приведенное равенство не будет выполняться для ближайшего соседнего числа (fExpected =

 

14

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

10000,000977). Это особенно актуально, если в программе имеется преобразование из одинарной точности в двойную.

Пусть x — вычисляемое значение, а e — его погрешность. В численных алгоритмах малость ошибки сравнивается с ответом. Такая формулировка приводит к следующей реализации:

fabs(e) < eps * fabs(x).

В этой реализации абсолютный порог малости числа зависит от значения величины, с которой она сравнивается — при больших по модулю значениях x даже относительно большие e будут признаны малыми. Действительно, число 1 мало по сравнению с 1e6 в той же степени, что и число 1e-6 по сравнению с 1.

И эта реализация может приводить к проблемам, но уже в случае малых по абсолютной величине чисел x. Если x — почти нуль, то и правая часть получается почти нулевой. В этом случае правая часть может оказаться настолько малой, что никакое e не сможет удовлетворить неравенству. Эту проблему решает такая реализация:

fabs(e) < eps * (1.0 + fabs(x)).

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

fabs(e) < (eps + 2.0 * FLT_EPSILON) * (1.0 + fabs(x)).

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

float x; // вычисляемая величина

 

15

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

float e; // ошибка ответа

x = ...; // вычисляем первое приближение e = ...; // вычисляем ошибку

// пока ошибка велика по отношению к ответу

while( fabs(e) > (eps + 2.0 * FLT_EPSILON) * (1.0 + fabs(x)) ){ x = ...; // вычисляем новое приближение

e = ...; // вычисляем новое значение ошибки

}

Сравнение на равенство двух вещественных чисел

. При сравнении чисел x и y на равенство фактически проверяется разность x - y

на малость. Если числа x и y равноправны, то обычно их считают равными, если разность x - y мала по сравнению с максимальным по абсолютной величине из чисел x

и y:

fabs(x - y) < (eps + 2.0 * FLT_EPSILON) * (1.0 + fmax(fabs(x), fabs(y))),

где fmax() — функция, возвращающая значение максимального из своих аргументов.

Переполнение и потеря значимости

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

Потеря точности при вычитании

При нахождении разности близких по величине чисел может происходить потеря точности. Пусть в 4-разрядной арифметике два непредставимых числа X и Y

оказались представленными числами x = 1.001 и y = 1.002. В обоих случаях относительная погрешность представления принимает значения порядка машинного эпсилон (eps = 0.001). Вычислим относительную погрешность разности z = y - x = 0.001:

 

16

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

|(y-x)-(Y-X)|/|Y-X| = 2 * eps / 0.001 = 2000 * eps.

Таким образом, вычисленная разность не содержит ни одной верной цифры.

Выводы

При работе с вещественными числами необходимо использовать корректную проверку на равенство.

Погрешности, связанные с неточным представлением вещественных чисел,

имеют тенденцию накапливаться.

В машинной вещественной арифметике нарушаются даже простейшие свойства чисел (например, коммутативность сложения).

1.2.6 Представление текстовых данных в памяти компьютера

Кодировки ASCII и UNICODE

Все используемые способы представления текстовых данных в памяти ЭВМ сводятся к нумерации символов алфавита и хранения полученных целых чисел наравне с обычными числами. Способ нумерации называется кодировкой, а числа -

кодами символов.

Самая распространенная система кодирования латиницы - ASCII - использует 7

бит на символ. В кодировке ASCII (American Standard Code for Information Interchange -

Американский стандартный код обмена информацией) все символы латиницы, цифры и большинство распространенных знаков препинания обозначаются кодами от 0 до

127, при этом коды букв расставлены в соответствии с латинским алфавитом.

Другие алфавиты обычно кодируются более сложным образом: символы алфавита получают коды в диапазоне от 128 до 255, а коды от 0 до 127 соответствуют кодам ASCII. Любой символ этих алфавитов может быть представлен 8-ю битами.

Для представления кириллицы существует три основных кодировки: cp866,

ср1251 и KOI-8.

Двух байтов, в принципе, достаточно, чтобы сформировать единую кодировку для всех современных алфавитов и основных подмножеств иероглифики. Unicode.

 

17

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

Для просмотра текстовых данных в памяти компьютера можно использовать hex-редактор («hex» - шестнадцатеричный).

Hex-редактор () — приложение для редактирования данных, в котором данные представлены в «сыром виде» — как последовательность байтов. В качестве примера рассмотрим встроенный hex-редактор в файловом менеджере Far. Чтобы просмотреть бинарный файл необходимо нажать клавишу «F4» и перейти в смешанный режим просмотра еще одним нажатием клавишу «F4». Содержимое бинарного файла представлено на рисунке.

Рисунок – Просмотр содержимого бинарного файла в hex-редакторе файлового менеджера Far.

Hex-редактор отображает данные в виде матрицы, каждая ячейка которой соответствует одному байту, записанному в шестнадцатеричной системе счисления в виде двухзначного числа (с ведущим нулём, если он требуется).

Справа от матрицы могут отображаться те же данные, но в другой интерпретации. Наиболее часто используется альтернативное отображение данных как текста в кодировке ASCII (на рисунке показаны цветом фуксия), при этом байты,

значения которых соответствуют непечатным символам, отображаются как точки (·).

1.3 Ход работы

1.3.1 Этапы выполнения лабораторной работы

1. Ознакомиться с теоретической частью.

 

18

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

2. Установить порядок байт в многобайтном целом числе в представлении на лабораторной машине (Example 1, исходные коды для анализа: «integers.h» - функция printByteOrder(), «general.h», «main.cpp»).

3. Выбрать два целых двузначных числа, осуществить над ними операцию вычитания в аналитическом виде (в виде ручного расчета) и виде функции на языке С/С++. Сравнить аналитический результат с результатами работы программы.

Отобразить ручной расчет, программный код и результаты его работы в отчете.

Можно добавить соответствующий исходный код в Example 1 в файле integers.h в

функцию printByteOrder().

int a = 27; int b = 49; int c = a – b;

printf("Convert num to binary with getBits() function\n"); for (int i = 31; i > -1; i--) {

printf("%u", getBits(с, i));

}

4. Вывести на печать все биты каждого числа из Example 2 (integers.h, convertIntNumbers()). Получить доступ к произвольному биту результата и инвертировать его. Представить результат.

int a = 27;

 

int b = 49;

 

int c = a – b;

 

char buffer[65];

// Буфер для хранения строкового представления числа

int r = 2;

// Основание новой системы счисления

_itoa(c, buffer, r);

printf("Base %d: num_%d = %s (%d chars)\n", r, r, buffer, 65); printf("Convert num to binary with getBits() function\n"); for (int i = 31; i > -1; i--) {

printf("%u", getBits(num, i));

}

c ^= (1 << 5); // Инвертирование 5-го бита результата

// Повторный вывод числа с

 

19

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

5. Реализовать с помощью библиотечных функций перевод целого числа в строковое представление 2, 3, 8, 16 системы счисления (модифицировав Example 2).

Результат отобразить в отчете: программный код и вывод на экран.

char buffer[65];

//

Буфер для

хранения строкового представления числа

int r = 2;

//

Основание

новой системы счисления

_itoa(c, buffer, r);

printf("Base %d: num_%d = %s (%d chars)\n", r, r, buffer, 65);

6.Реализовать прямой и обратный программный перевод вещественного числа

сплавающей запятой в представление в формате IEEE754 с одинарной точностью

(взять Example 3 из программы для чисел 0xDEADBEEF= -6.2598534E18f и остальных,

приведенных в комментариях. Функция convertFloatNumbers()). Для контроля правильности операций использовать программу [2].

ParsedFloat ft;

//ft.value = -25.625; ft.value = 155.625;

//ft.value = -6.2598534E18f;

//ft.value = -0.34375f;

7.Выполнить и объяснить результаты Example 4-10. Оценить количество верных знаков после запятой.

8.Разобраться в работе функции getBits и обратном переводе числа из формата

IEEE754 в число плавающей запятой. Выяснить роль сдвигов числа 2 на произвольное

число позиций вправо и влево, освоить работу с побитовыми логическими

операциями.

9.Изучить формат представления текстовых данных в ЭВМ.

10.Запустить файловый менеджер Far и перейти в директорию ProccessMemory.

Спомощью встроенного просмотрщика и hex-редактора (вызывается нажатием клавиши F4) найти заголовок диалогового окна приложения slave.exe и

проанализировать формат представления строки в виде набора байт. Скриншот hex-

редактора привести в отчете.

11. Запустить файл slave.exe из директории ProccessMemory, затем запустить файл master.exe

 

20

Д.И. Кардаш, А.М. Вульфин

Лабораторные работы СВТ

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]