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

ЛР-2 / ЯП №2

.odt
Скачиваний:
3
Добавлен:
15.05.2026
Размер:
410.98 Кб
Скачать

Министерство науки и высшего образования Российской Федерации

Федеральное государственное автономное образовательное учреждение

высшего образования

ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОНИКИ (ТУСУР)

Кафедра безопасности информационных систем (БИС)

ВЕЩЕСТВЕННЫЕ ЧИСЛА. ОШИБКИ ПРИ РАБОТЕ С ВЕЩЕСТВЕННЫМИ ЧИСЛАМИ

Отчет по лабораторной работе №2

по дисциплине «Языки программирования»

Студент гр.

_______

_______

Принял:

Доцент каф. КИБЭВС, д.т.н., доцент

_______ Романов А. С.

_______

Оглавление

Введение 3

1 Ход работы 4

Заключение 13

Приложение А 14

Введение

Целью работы является знакомство с основными ошибками, возникающими при обработке вещественных чисел.

Для выполнения работы был выбран ЯП Python.

Задание:

1. Изучить теоретические сведения.

2. В качестве исходных значений принять следующие значения:

x = <номер студенческого билета><номер группы>,<дата рождения ддммгггг>;

y = x * 10-10;

c = x + y;

c’ = округление с до 9 знака после запятой;

z = x ± 10-8 ;

k = округлить до целого(х).

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

3. Объяснить полученные результаты.

4. Для выбранного варианта задания изучить, какие типы данных есть в языке программирования, как они реализованы.

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

6. Написать отчет и защитить у преподавателя.

1 Ход работы

Ниже приведены точные расчеты чисел:

x = 24730187341,24022006;

y = x*10-10 = 2,473018734124022006;

c = x+y = 24730187343,713238794124022006;

c’ = 24730187343,713238794;

z1 = x+10-8 = 24730187341,24022007;

z2 = x-10-8 = 24730187341,24022005;

k = 24730187341.

Существуют три основные ошибки вычислений, возникающие при выполнении операции над вещественными числами:

  1. Исчезновение операнда – операнд может исчезнуть, если он относительно мал по отношению с другим операндом. В данной работе можно увидеть данную ошибку при вычислении чисел z1 и z2.

  2. Умножение ошибки – многократное увеличение абсолютной погрешности операнда, которая может появиться при использовании арифметики с плавающей точкой, даже если относительная ошибка мала. Зачастую это является результатом умножения или деления. Данная ошибка наблюдается при вычислении y.

  3. Потеря значимости – полная потеря значимости, вызванная вычитанием почти равных чисел.

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

Рисунок 1.1 — Запрограммированная последовательность вычислений

Рисунок 1.2 — Результаты вычислений на ЯП Python

При вычислении числа «x», с помощью программы мы получили x = 24730187341,24021912. Следовательно, можно сделать вывод, что абсолютная ошибка при расчете равна 0,00000094, а относительная ошибка равна 0,000000000000000380102.

При вычислении числа «y» получили y = 2,473018734124022178, из чего можно сделать вывод, что абсолютная ошибка равна 0,000000000000000172, а относительная – 0,0000000000000000695508.

Во время расчета числа «c» получили c = 24730187343,713237762451171875. В данной ситуации абсолютная ошибка равна 0,000001031672850131, а относительная 0,00000000000000004172. При округлении числа c до 9 знаков после запятой получилось c’ = 24730187343,713237762. Это означает, что абсолютная ошибка равна 0,000001032, а относительная – 0,0000000000000000417298.

Числа «z1» и «z2» получились равными 24730187341.240219116210938. Следовательно, абсолютная ошибка равна 0.000000953789062 и 0,000000933789062 соответственно, а относительная ошибка равна 0.000000000000000038565 и 0.000000000000000037755 соответственно.

При округлении числа до целого ошибки отсутствуют.

Также по заданию были разобраны примеры и приведены коды их решения на ЯП Python (рисунок 1.3-1.14)

Рисунок 1.3 — Код для ошибки Исчезновение операнда

Рисунок 1.4 — Вывод для кода ошибки 1

Видно, что значения совпадают, следовательно сложение и вычитание 10-8 не дает ничего, операнд пропадает.

Рисунок 1.5 — Код для ошибки Умножение ошибки

Рисунок 1.6 — Вывод для кода ошибки 2

Видно, что при изменении числа на очень малую величину, их квадраты отличаются.

Рисунок 1.7 — Код для ошибки Потеря значимости

Рисунок 1.8 — Вывод для кода ошибки 3

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

Р исунок 1.9 — Код для Программный вывод битов (IEEE 754)

Р исунок 1.10 — Вывод для Программный вывод битов (IEEE 754)

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

Р исунок 1.11 — Код для Определение машинного эпсилона

Рисунок 1.12 — Вывод для Определение машинного эпсилона

Как видно из вывода, было реализовано определение машинного эпсилона и судя по тому что значение совпало с ulp из math, реализовано верно.

Рисунок 1.13 — Код для Метода Кахана

Рисунок 1.14 — Вывод для Метода Кахана

Как можно видеть, точная сумма находится верно, тогда как обычная имеет ошибку.

Всего в языке программирования Python есть 8 типов данных:

  1. int – целые числа;

  2. float – числа с плавающей точкой;

  3. complex – комплексные числа (числа вида a + b*i, где a и b – вещественные числа, а i – мнимая единица, т.е. число для которого выполняется i^2 = -1);

  4. string – строки;

  5. bool – логический тип;

  6. list – списки;

  7. tuple – кортежи;

  8. dict – словари;

  9. set – множества.

В данной работе использовался тип данных float, который отвечает за числа с плавающей точкой. Переменная такого типа может принимать значения от 2.2^-308 до 1.7^308. Переменные типа int как и в других языках могут принимать значения от -2 147 483 648 до 2 147 483 648.

Заключение

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

Приложение А

(обязательное)

Листинг кода для лабораторной работы

from math import *

x = float(24730187341.24022006)

y = x * float(10**-10)

c = x + y

z1 = x + float(10**-8)

z2 = x - float(10**-8)

k = floor(x)

print(f'x = {x:.8f}')

print(f'y = x*10^-10 = {y:.18f}')

print(f'c = x+y = {c:.18f}')

print(f'c1 = округлить c до 9 знаков = {round(c,9):.9f}')

print(f'z+ = x+10^-8 = {z1:.15f}')

print(f'z- = x-10^-8 = {z2:.15f}')

print(f'k = floor(x) = {k}')

print('\n' + ' '*60)

print('ОШИБКА 1: ИСЧЕЗНОВЕНИЕ ОПЕРАНДА')

print(' '*60)

print(f'x = {x:.8f}')

print(f'z+ = {z1:.8f}')

print(f"z- = {z2:.8f}")

print('\n' + ' '*60)

print('ОШИБКА 2: УМНОЖЕНИЕ ОШИБКИ')

print(' '*60)

m = y*(10**3)

n = y*(10**3)+0.000001

z = m*m

v = n*n

print(f'm = {m:.9f}')

print(f'n = {n:.9f}')

print(f'z = m*m = {z:.9e}')

print(f'v = n*n = {v:.9e}')

print('\n' + ' '*60)

print('ОШИБКА 3: ПОТЕРЯ ЗНАЧИМОСТИ')

print(' '*60)

g = c

h = x

print(f'g = {g:.8f}')

print(f'h = {h:.8f}')

print(f'g - h = {g - h:.8f}')

print(f'y = {y:.8f}')

print("\n" + " " * 60)

print("Представление чисел в памяти (IEEE 754)")

import struct

def float_to_bits(f):

"""Преобразование float в битовое представление"""

s = struct.pack('>d', f)

i = struct.unpack('>q', s)[0]

return bin(i)[2:].zfill(64)

def print_float_bits(value, name):

bits = float_to_bits(value)

sign = bits[0]

exponent = bits[1:12]

mantissa = bits[12:]

print(f"\n{name} = {value}")

print(f" Биты: {bits}")

print(f" Знак: {sign} | Экспонента: {exponent} | Мантисса: {mantissa[:13]}...")

x = 12345.678

small = 0.0000001

print_float_bits(x, "x")

print_float_bits(x + small, "x + small")

print_float_bits(x, "x (снова)")

print(f"\nБиты x и x+small одинаковы? {float_to_bits(x) == float_to_bits(x + small)}")

print('\n' + ' '*60)

print('МАШИННЫЙ ЭПСИЛОН')

# float (Python float = double precision)

epsilon_float = 1.0

while 1.0 + epsilon_float / 2.0 > 1.0:

epsilon_float /= 2.0

print(f"Машинный эпсилон (float64): {epsilon_float}")

print(f"Теоретическое значение: {2**-52:.16e}")

# Проверка с помощью math.ulp

print(f"math.ulp(1.0) = {ulp(1.0)}")

print(f"Разница между двумя числами float64: {ulp(1.0)-epsilon_float}")

print('\n' + ' '*60)

print("Метод Кахана для точного суммирования")

def kahan_sum(numbers):

s = 0.0

c = 0.0 # Поправка

for num in numbers:

y = num - c

t = s + y

c = (t - s) - y

s = t

return s

# Создаем массив чисел

n = 1000000

numbers = [0.1234567] * n

# Обычная сумма

simple_sum = 0.0

for num in numbers:

simple_sum += num

# Метод Кахана

kahan = kahan_sum(numbers)

exact_sum = 0.1234567 * n

print(f"Точная сумма: {exact_sum}")

print(f"Обычная сумма: {simple_sum}")

print(f"Метод Кахана: {kahan}")

print(f"Ошибка обычной суммы: {abs(exact_sum - simple_sum)}")

print(f"Ошибка метода Кахана: {abs(exact_sum - kahan)}")

15

Соседние файлы в папке ЛР-2