C++ для «чайников» - страница 29

стр.

множество ).

Тип float, представляющий в С++ действительные числа, не является перечислимым. Кроме того, в отличие от действительных чисел, числа с плавающей точкой имеют ограниченное количество разрядов, поэтому при использовании операторов сравнения с числами с плавающей точкой необходимо соблюдать осторожность. Рассмотрим следующий пример:


    float f1 = 10.0 ;

    float f2 = f1 / 3 ;

    f1 == ( f2 * 3.0 ) ; /* Равны ли эти значения? */


__________________

>9Более того, в данном случае это не красивое слово, а строгий математический термин. — Прим. ред.

_________________

58 стр. Часть 1. Первое знакомство с С++


Сравнивая начальное и полученное значения, мы не обязательно получим равенство. Действительные переменные, с которыми работает компьютер, не могут содержать бесконечное число значимых разрядов. Поэтому f2 равняется, например, 3.3333, а не 3>1/>3. В отличие от математики, в компьютере число троек после точки ограничено. Умножив 3.3333 на 3, вы, вероятно, получите не 10.0, а 9.9999. Такой маленькой разницей может пренебречь человек, но не компьютер. Эта машина понимает под равенством исключительно точное равенство значений.

«Переменная типа float поддерживает точность около 6 значащих цифр, а double — 13. Я говорю "около", так как компьютер часто генерирует числа наподобие 3.3333347 из-за особенностей вычислений с плавающей точкой.»

[Технические подробности]

В "чистой" математике количество троек после десятичной точки бесконечно, но компьютер не в состоянии работать с бесконечными числами. Поэтому при умножении 3.3333 на 3 мы получим 9.9999, а не 10, которое должно получаться при умножении 3>1/>3 на 3 — так называемая ошибка округления. Такие малые отличия двух чисел несущественны для человека, но не для компьютера. Равенство означает в точности точное равенство ( неплохой каламбур? ).

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

Проблемы могут появиться и при совершенно простых вычислениях, например:


      float f1 = 10.0 ;

      float f2 = 100 % 30 ;

      f1 == f2 ; /* истинно ли это выражение? */


Теоретически f1 и f2 должны быть равны ( об операции деления по модулю можно прочитать в главе 3, "Выполнение математических операций" ). Ошибка округления возникнуть вроде бы не должна. Однако и в этом нельзя быть уверенным: вам ведь неизвестно, как именно представляются числа с плавающей точкой внутри компьютера. Позвольте порекомендовать более безопасное сравнение:


      float f1 = 10.0 ;

      float f2 = f1 / 3 ;

      float f3 = f2 * 3.0 ;

      ( f1 - f3 ) < 0.0001 &&( f3 - f1 ) < 0.0001 ;


Оно истинно в том случае, если разница между f1 и f2 меньше какого-то малого значения ( в нашем случае — 0.0001 ); при этом небольшие погрешности вычислений на правильность сравнения не повлияют.

Сокращённые вычисления в С++...59

Рассмотрим следующую конструкцию:


      условие1&&условие2 


Если условие1 ложно, то результат не будет истинным, независимо от истинности выражения условие2. В схеме


      условие1 || условие2


в случае истинности выражения условие1 неважно, какое значение принимает условие2, — результат будет истинным.

Для экономии времени С++ вычисляет первым условие1, и в случае, если оно ложно ( для оператора && ) или истинно ( для оператора || ), выражение условие2 не вычисляется и не анализируется.

_________________

59 стр. Глава 4. Выполнение логических операций


►Бинарные числа в С++...60

Переменные хранятся в компьютере в виде так называемых двоичных, или бинарных, чисел, т.е. представлены в виде последовательности битов, каждый из которых может содержать два значения: 0 или 1. Скорее всего, вам не придётся оперировать с числами на битовом уровне, хотя существуют ситуации, когда обойтись без этого нельзя. С++ снабжён несколькими операторами для подобных целей.

«Вряд ли вам придётся часто работать с переменными на битовом уровне, поэтому остальную часть главы следует рассматривать как техническое отступление от основного повествования.»