«Переменная типа float поддерживает точность около 6 значащих цифр, а double — 13. Я говорю "около", так как компьютер часто генерирует числа наподобие 3.3333347 из-за особенностей вычислений с плавающей точкой.»
В "чистой" математике количество троек после десятичной точки бесконечно, но компьютер не в состоянии работать с бесконечными числами. Поэтому при умножении 3.3333 на 3 мы получим 9.9999, а не 10, которое должно получаться при умножении 31/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. Скорее всего, вам не придётся оперировать с числами на битовом уровне, хотя существуют ситуации, когда обойтись без этого нельзя. С++ снабжён несколькими операторами для подобных целей.
«Вряд ли вам придётся часто работать с переменными на битовом уровне, поэтому остальную часть главы следует рассматривать как техническое отступление от основного повествования.»
Так называемые побитовые логические операторы работают с аргументами на битовом уровне. Для того чтобы понять принципы их работы, давайте рассмотрим, как компьютер хранит переменные.
Десятичная система счисления...60
Числа, которыми мы чаще всего пользуемся, называются десятичными, или числами по основанию 10. В большинстве случаев программисты на С++ тоже используют десятичные переменные. Например, мы говорим, что значение переменной var равно 123.
Число 123 можно представить в виде 1*100+2*10+3*1. При этом каждое из чисел 100, 10, 1 является степенью 10.