Пн. Июн 1st, 2026
Представление вещественных чисел

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

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

Вещественное число — число с дробной частью, которое может быть представлено в экспоненциальной форме: \( A = m \times q^p \), где:

  • \( m \) — мантисса (значащая часть числа)
  • \( q \) — основание системы счисления
  • \( p \) — порядок (экспонента)

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

Знак
Порядок
Мантисса
Знак числа (1 бит): 0 — положительное, 1 — отрицательное
Порядок (экспонента) — определяет масштаб числа
Мантисса — значащие цифры числа

Нормализованная запись числа

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

\( \frac{1}{q} \leq |m| < 1 \)

Это означает, что первая цифра мантиссы после запятой в системе счисления с основанием q всегда отлична от нуля.

Пример: Представим число 123.45 в нормализованном виде:

\( 123.45 = 0.12345 \times 10^3 \)

Здесь мантисса = 0.12345, порядок = 3

Формат IEEE 754

Стандарт IEEE 754 определяет форматы представления чисел с плавающей запятой. Наиболее распространенные:

Тип Общий размер (бит) Разрядность мантиссы Разрядность порядка Смещение порядка
Single (float) 32 23 бита 8 бит 127
Double (double) 64 52 бита 11 бит 1023

Пример представления числа 13.25 в формате IEEE 754 (single precision):

  1. Преобразуем в двоичную систему: 13.2510 = 1101.012
  2. Нормализуем: 1.10101 × 23
  3. Определяем части:
    • Знак: 0 (число положительное)
    • Порядок: 3 + 127 = 130 = 100000102
    • Мантисса: 10101000000000000000000 (23 бита)

Представление числа 13.25 в формате IEEE 754 (32 бита)

0
10000010
10101000000000000000000

Диапазон значений вещественных чисел

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

Тип Минимальное по модулю Максимальное по модулю Десятичных знаков
Single (float) 1.2 × 10-38 3.4 × 1038 7-8
Double (double) 2.2 × 10-308 1.8 × 10308 15-16

Особые значения:

  • Ноль: все биты порядка и мантиссы равны 0
  • Бесконечность: все биты порядка равны 1, мантисса равна 0
  • NaN (Not a Number): все биты порядка равны 1, мантисса не равна 0

Проблемы хранения вещественных чисел

Из-за ограниченного количества разрядов мантиссы возникают проблемы точности представления чисел.

Пример потери точности:

Число 0.110 в двоичной системе представляется как бесконечная периодическая дробь:

0.110 = 0.000110011001100110011…2

При сохранении в формате float (23 бита мантиссы) происходит обрыв и потеря точности.

Основные проблемы:

  • Округление при преобразовании из десятичной в двоичную систему
  • Потеря точности при выполнении арифметических операций
  • Накопление ошибок при последовательных вычислениях
  • Проблемы сравнения чисел из-за ошибок округления

Накопление ошибок при вычислениях

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

Пример накопления ошибки:

Вычисление суммы 1000000 раз числа 0.1:

// Псевдокод
сумма = 0.0
для i от 1 до 1000000:
    сумма = сумма + 0.1
результат = сумма // Ожидается 100000.0, но будет небольшая погрешность

Как уменьшить накопление ошибок:

  • Использовать тип данных с большей точностью (double вместо float)
  • Избегать вычитания близких по величине чисел
  • Минимизировать количество операций
  • Использовать алгоритмы, устойчивые к ошибкам округления

Пример проблемы вычитания:

Вычисление \( y = \sqrt{x^2 + 1} — 1 \) при малых x

При x → 0,00… вычисление приводит к потере точности. Лучше использовать эквивалентное выражение:

\( y = \frac{x^2}{\sqrt{x^2 + 1} + 1} \)

Практические рекомендации

При работе с вещественными числами:

  • Всегда помните о возможной потере точности
  • Избегайте прямого сравнения на равенство (вместо \( a == b \) используйте \( |a — b| < \varepsilon \))
  • Используйте подходящий тип данных в зависимости от требуемой точности
  • Старайтесь избегать алгоритмов, усиливающих ошибки округления

Пример безопасного сравнения:

// Вместо:
if (a == b) { … }

// Используйте:
epsilon = 1e-10; // Малая величина
if (abs(a — b) < epsilon) { ... }