СИ. Программирование на языке CC Часть Структурное программирование
Скачать 1.65 Mb.
|
# i n c l u d e using namespace std ; i n t main () { — 45 — double x =123.546789, y = 3.1415926; cout << scientific << setw (14) << setprecision (4) << x << ",␣" << y << endl ; cout << fixed << setw (12) << setprecision (5) << x << ",␣" Рис. 2.1. Экран программы из листинга. Системы счисления. Кодирование чисел Позиционные системы счисления. Для представления чисел обычно используются позиционные системы счисления, в которых значение каждой цифры в записи числа определяется позицией этой цифры = 𝑛−1 ∑︁ 𝑖=0 𝑎 𝑖 · 𝑑 𝑖 = 𝑎 𝑛−1 · 𝑑 𝑛−1 + . . . + 𝑎 1 · 𝑑 1 + 𝑎 0 · где 𝑎 𝑖 — я цифра числа, 𝑎 𝑖 = 0, 1, . . . , 𝑑 − 1 ; 𝑛 — разрядность числа 𝑑 — основание системы счисления (в двоичной системе 𝑑 = 2; в десятичной 𝑑 = 10; в восьмеричной 𝑑 = 8; в шестнадцатеричной 𝑑 = 16). Для представления чисел в позиционной системе по основанию 𝑑 используется 𝑑 различных цифр от до (𝑑 − 1). Используя 𝑛 разрядов, можно записать различных чисел от до Двоичная система счисления. В двоичной системе 𝑑 = 2; для записи чисел используются только две цифры 0 и 1. Это очень удобно сточки зрения аппаратной реализации цифровых устройств они должны находиться только — 46 в двух возможных состояниях включено и выключено. Каждая цифра двоичного числа (двоичный разряд) называется битом. Биты нумеруются справа налево, от 0 до 𝑛 − 1. Нулевой (самый правый) бит называется младшим significant digit, LSD); последний (самый правый, с весом 𝑛 − 1) бит называется старшим (most significant digit, Числа, представленные в двоичном виде, легко умножать или делить на 2 — эти операции эквивалентны сдвигу числа влево (младший бит получившегося числа принимает нулевое значение) или вправо (младший бит исходного числа при этом теряется). Перевод чисел из двоичной системы в десятичную. Производится по формуле ( 2.1 ). Например 2 = 1 · 2 3 + 0 · 2 2 + 1 · 2 1 + 1 · 2 0 = (8 + 0 + 2 + 1) 10 = 11 Пример перевода двоичного числа, содержащего как целую, таки дробную часть 2 = 1 · 2 2 + 1 · 2 1 + 0 · 2 0 + 1 · 2 −1 + 0 · 2 −2 + 1 · 2 −3 = 5,625 Перевод чисел из десятичной системы в двоичную. Для перевода целого десятичного числа в двоичное необходимо выполнить последовательные деления надо тех пор, пока остаток после очередного деления не станет меньше 2 (риса в качестве ответа берут все полученные остатки в обратном порядке от последнего до первого (начиная с последнего результата деления). Чтобы перевести дробное число (с нулевой целой частью, рис. 2.2 б), необходимо, наоборот, умножать исходное десятичное число на 2 и брать в качестве очередной цифры результата целую часть произведения, а дробную часть использовать для дальнейшего умножения до тех пор, пока не будет достигнута нужная точность или не получится нулевой результат. Заметим, что конечная десятичная дробь может (как в нашем примере) превратиться в бесконечную двоичную, ноне наоборот — 47 Для перевода числа, содержащего как целую, таки дробную часть, необходимо осуществить перевод целой и дробной частей в отдельности. Восьмеричная система счисления. В восьмеричной системе 𝑑 = 8; для записи чисел используются восемь цифр от 0 до 7 включительно. Всё вышесказанное относительно перевода чисел относится и к восьмеричной системе счисления, достаточно только деление (умножение) на 2 заменить, соответственно, делением (умножением) на Шестнадцатеричная система счисления. В шестнадцатеричной системе для представления чисел необходимо использовать шестнадцать различных цифр. Поэтому для цифр после девяти применяют буквы латинского алфавита 𝑎, 𝑏, 𝑐, 𝑑, 𝑒, 𝑓 , соответственно, для 10, 11, 12, 13, 14 и Метод подстановки. Т. к. числа в двоичном представлении состоят из большого количества нулей и единиц, то для облегчения восприятия их удобнее записывать в другой системе счисления, основание которой является степенью двойки, например, в восьмеричной или шестнадцатеричной системе. Дело в том, что для взаимного перевода между этими системами можно использовать метод подстановки, не нуждающийся в последовательных делениях или умножениях. Достаточно запомнить таблицу соответствия для первых шестнадцати двоичных чисел (табл. 2.1 ). а б Рис. 2.2. Перевод десятичного числа в двоичное — 48 Таблица 2.1. Таблица соответствия чисел в различных системах счисления Двоичное Десятичное Шестнадцатеричное Восьмеричное 0 0 0 0001 1 1 1 0010 2 2 2 0011 3 3 3 0100 4 4 4 0101 5 5 5 0110 6 6 6 0111 7 7 7 1000 8 8 10 1001 9 9 11 1010 10 𝑎 12 1011 11 𝑏 13 1100 12 𝑐 14 1101 13 𝑑 15 1110 14 𝑒 16 1111 Для перевода двоичного числа в шестнадцатеричное надо разбить исходное число на тетрады группы по четыре двоичных разряда, при необходимости дополнив целую часть числа нулевыми битами слева, а дробную часть — справа, и осуществить перевод каждой тетрады в отдельности в соответствии с табл. Например 1100 0010 2 = 𝐴𝐶2 16 ; 0010 0110 , 0100 1000 2 = 26, 48 Для перевода в восьмеричную систему надо также поступить с группами потри двоичных разряда (т. к. 2 3 = Обратный перевод осуществляется аналогично, например 16 = 0101 1100 1000 2 ; 327 8 = 010 010 111 8 — 49 — Двоично-десятичное представление чисел coded decimal, BCD) — форма записи целых чисел, когда каждый десятичный разряд числа записывается в виде его четырёхбитного двоичного кода. Например, десятичное число 37 будет записано в двоичной системе счисления как 0010 0101 а в двоично-десятичном коде — как 0011 0111 𝐵𝐶𝐷 Двоично-десятичное представление занимает больше памяти, чем двоичное (каждые четыре бита кода BCD представляют всего 10 различных комбинаций вместо 16), но числа, представленные в формате BCD, проще перевести в десятичный вид (методом подстановки при переводе чисел с дробной частью не теряется точность числа проще умножать или делить на Обратный код. Обратный код применяется для представления отрицательных двоичных чисел. Обратный код отрицательного числа образуется пут м инвертирования всех разрядов модуля исходного двоичного числа. Например, если записать число 5 в двоичном разрядном виде, то получится. Следовательно, отрицательное число −5 в обратном коде выглядит как 1010. Единица в старшем разряде — признак отрицательного числа. Для обратного перевода нужно снова инвертировать все биты, получится опять Положительные числа в обратном коде не изменяют свой вид. Дополнительный код. Дополнительный код применяется для представления отрицательных двоичных чисел. Чтобы записать дополнительный код отрицательного числа, надо инвертировать все разряды модуля исходного двоичного числа (как ив случае обратного кода, а затем прибавить к результату (учитывая все переносы в старшие разряды). Число −5 в дополнительном коде 1010 + 1 = 1011. Единица в старшем разряде — признак отрицательного числа. Для обратного перевода нужно снова инвертировать все биты и прибавить 1, получится опять 0100 + 1 = Другой пример −6 10 → 0110 2 → 1001 2 + 1 = Положительные числа в дополнительном коде не изменяют свой вид — 50 Представление вещественных чисел. Любое число 𝑥 в системе счисления с основанием 𝑑 можно записать в виде 𝑥 = 𝑠 · 𝑚 · 𝑑 𝑝 , где 𝑠 = 1 или −1 — задаёт знак числа 𝑚 — множитель, содержащий все цифры числа (мантисса целое число, называемое порядком. Такой способ записи чисел называется представлением числа с плавающей точкой. Например, вещественное число 123.4567 = 1.234567 · 10 2 = 0.1234567 · 10 3 . Вещественные числа при вводе и выводе обычно представляются в десятичной форме и записываются в виде, нов памяти компьютера значения мантиссы и порядка хранятся в двоичной системе счисления. Вещественное число называется нормализованным, если мантисса лежит в пределах 1 6 𝑚 < 𝑑. При 𝑑 = 2 первый бит мантиссы нормализованного числа всегда равен единице, поэтому он обычно не хранится в памяти компьютера (для экономии места). Международный стандарт IEEE 754 (IEC 60559:1989) определяет три типа чисел с плавающей точкой: real*4 , real*8 и real*10 , которые занимают в памяти 4, 8 и 10 байт соответственно (в языке C/C++ это типы float , double и Во всех трёх типах в самом старшем бите первого байта хранится знак числа (1 для отрицательных, 0 для положительных чисел). Для типа остальные семь бит первого байта и старший бит второго байта отводятся под хранение двоичного представления порядка десятичного числа. Порядок хранится в памяти со смещением 127, те. нулевое значение в памяти соответствует значению порядка −127. Оставшиеся 23 бита бит второго байта и все биты третьего и четвёртого байтов) отводятся под мантиссу. Старший бит мантиссы подразумевается, ноне хранится (т. е. реально мантисса в этом формате представляется 24 битами). Для типа порядок занимает 11 бит (7 бит первого байта и 4 бита второго. Порядок представляется со смещением 1023. Мантисса занимает бита (плюс единичный старший бит, который не хранится, но подразумевается Для типа порядок занимает 15 бит (7 бит первого байта и 8 бит второго. Смещение порядка 16383. Мантисса занимает 64 бита (единичный старший битв отличие от предыдущих форматов, хранится в памяти. Логические выражения Логический тип данных. Переменная логического типа bool по определению может принимать только два возможных значения: true (истина) и ложь. В памяти компьютера логическая переменная занимает 1 байт; любое ненулевое значение трактуется как true , нулевое значение обозначает false . Ниже для краткости будем вместо true писать 1, а вместо false — Логические операции. Элементарные логические операции) Отрицание (унарная операция НЕ, NOT) инвертирует логическое значение, те. заменяет его на противоположное ¬0 = 1; ¬1 = 0; 2) Дизъюнкция (логическое сложение, бинарная операция ИЛИ, OR) двух логических значений равна единице, если хотя бы одно из значений равно единице 0 ∨ 0 = 0; 0 ∨ 1 = 1; 1 ∨ 0 = 1; 1 ∨ 1 = 1; 3) Конъюнкция (логическое умножение, бинарная операция И, AND) двух логических значений равна нулю, если хотя бы одно из значений равно нулю ∧ 0 = 0 ; 0 ∧ 1 = 0; 1 ∧ 0 = 0; 1 ∧ 1 = Из перечисленных трёх операций можно определить любую другую логическую операцию, например, бинарную операцию Исключающее ИЛИ, которая даёт 0, если аргумента равны (те. оба имеют значение true или оба имеют значение false ), и 1 — если неравны В языке C/C++ логические операции NOT, OR и AND обозначаются, соответственно и « && ». Например && 0 = 0 , 1 && !0 = 1 , 1 || 0 = 1 — 52 Работа с битами на языке При работе с аппаратным обеспечением или для создания графических приложений часто приходится обращаться к отдельным битам переменных. Например, часто требуется установить вили сбросить в 0 некоторый бит, не изменив при этом состояние остальных битов. Напомним, что биты в байте нумеруются справа налево, начиная с нуля. Краткая сводка битовых операций на языке C/C++ приведена в табл. 2.2 , а в табл. 2.3 показаны результаты выполнения операций И, ИЛИ и Исключающее ИЛИ для всех возможных значений битов аргументов. Битовые (поразрядные) логические операции выполняются отдельно над каждой парой соответствующих битов своих операндов. Например, в результате выполнения операции x = 0 b00101001 & переменная примет значение 00100001 Для установки в 1, например, го бита переменной можно использовать операцию поразрядного ИЛИ или, что тоже самое Действительно, шестандцатеричное число 4 в двоичном виде записывается как 00000100 те во м бите операция ИЛИ сбитом даёт в результате Таблица 2.2. Битовые операции Обозначение Название Примеры Инверсия битов x = Поразрядное ИЛИ = a | b; y |= Поразрядное И = a & b; y &= x; ^ Поразрядное ИСКЛЮЧАЮЩЕЕ ИЛИ = a ^ b; y ^= Сдвиг влево x = a << Сдвиг вправо x = a >> b; — 53 Таблица 2.3. Таблица истинности битовых операций a b a | b a & b a ^ b 0 0 0 0 0 0 1 1 0 1 1 0 1 0 1 1 1 1 1 0 1 , независимо от состояния бита переменной x ; операция ИЛИ сбитом не изменяет соответствующий бит переменной Наоборот, для сброса в 0, например, го бита переменной можно использовать операцию поразрядного И или, что тоже самое Действительно, шестандцатеричное число DF в двоичном виде записывается как 11011111 те в м бите операция И сбитом даёт в результате, независимо от состояния бита переменной x ; операция И сбитом не изменяет соответствующий бит переменной Инвертирование битов производится с помощью операции поразрядное ИКЛЮЧАЮЩЕЕ ИЛИ (XOR), она обозначается ^. Например, чтобы инвертировать й и й бит переменной x , надо написать или, что тоже самое Действительно, число 5 в двоичном виде записывается как 00000101; операция сбитом инвертирует исходный бит операция XOR сбитом не изменяет соответствующий бит переменной Инвертировать сразу все биты переменной можно ещё проще x ; — 54 Для сдвига всех битов вправо на нужное число разрядов используется операция. Например, сдвиг вправо на один бит При этом младший бит теряется, а самый старший принимает значение 0 для положительных (или беззнаковых) переменных и 1 для отрицательных. Сдвиг влево обозначается <<. При этом самый старший бит теряется, а младший бит принимает значение Например, маску 00101001 для установки го, го иго бита можно записать следующим образом (1 << 5)| (1 << 3)| (1 << Пример 2.1. Вычисление значения логического выражения. В ли стинге 2.4 приведён пример консольного приложения, которое запрашивает с клавиатуры значения двух вещественных чисел и одно логическое значение, после чего вычисляет логическое выражение ∧ (𝑥 6 2) ∨ (2𝑦 = 10) ∧ (︁ 𝑥 4 ̸= 0.25 )︁ ∨ (𝑥𝑦 > Листинг 2.4: Вычисление значения логического выражения include 2 i n t main (){ 3 f l o a t x , y ; 4 bool a , f ; 5 printf ("\n=====␣Логическое␣выражение␣=====\n"); 6 printf ("Введите␣число␣x␣=␣"); 7 scanf ("%f",& x ); 8 printf ("Введите␣число␣y␣=␣"); 9 scanf ("%f",& y ); 10 printf ("Введите␣логическое␣значение␣a␣=␣"); 11 scanf ("%i", & a ); 12 f = a && ( x <= 2) || (2* y == 10) && ( x /4 != 0.25) 13 || ( x * y >= Результат — 55 Рис. 2.3. Пример вычисления логического выражения в программе Использование MathCAD для логических вычислений. Для проверки правильности работы программы удобно использовать рис. В MathCAD для представления логических значений true и используются числовые значения 1 и 0. Для ввода логических операций можно использовать кнопки панели инструментов «Логическая» (если её не видно, надо выполнить команду меню Вид í Панели инструментов Логическая) или комбинации клавиш Ctrl+Shift+6 для операции ИЛИ; Ctrl+Shift+6 для операции И; Ctrl+Shift+5 для операции Исключающее ИЛИ; Ctrl+Shift+1 для операции НЕ + для сравнения на равенство. Условные операторы Вычислительный процесс называют разветвляющимся, если в зависимости от выполнения некоторого условия он реализуется по одному из нескольких направлений. Напомним, что ветвление является одной из базовых алгоритмических конструкций структурного программирования (см. рис. 1.1 б). Для реализации разветвляющихся алгоритмов в языке C/C++ используется условный оператор если — 56 — i условие) { ... ; ... ; } e l s e { ... ; ... Условие задаётся логическим или целочисленным выражением и записывается обязательно в скобках. Если результат неравен нулю (те. имеет значение true — истина, то выполняется первый блок кода. В противном случае выполняется второй блок, указанный после ключевого слова иначе. Если первый или второй блок состоит всего из одного оператора, то фигурные скобки вокруг него можно не писать. Ветвь else необязательна если её опустить, то при нулевом значении условного выражения ( false — ложь) блок кода, указанный в операторе не выполняется, а управление передаётся следующим операторам. Пример 2.2. Если значение равно, то присвоить 𝑎 = 10, 𝑏 = 20, а иначе наоборот f ( k == 5 ) { // если k равно 5 a = 10; b = 20; } e l s e { // иначе a = 20; b = Обратите внимание, что сравнение на равенство записывается в виде двух знаков. Если вместо этого указать один символ «=», то получится оператор присваивания. Компилятор не выдаст сообщения об ошибке, поскольку в данном контексте оператор присваивания также допустим кроме самого присваивания он возвращает присвоенное значение, в результате такое условие в операторе if будет считаться истиной, если выражение, стоящее справа от знака «=», неравно нулю. Чтобы уберечь себя от подобной ошибки, иногда рекомендуют записывать сравнение на равенство в виде if(5 == k). Если здесь забыть о втором знаке «=», то получим ошибку вовремя компиляции. Пример 2.3. Тоже самое можно записать другим способом f ( k != 5 ) { // если k неравно иначе, те. если равно a = 10; b = Пример 2.4. В условном выражении можно использовать связки И (ИЛИ (||) и другие логические операции (см. табл. 1.2 на с f ( ( x <= 5) && ( x > -2) ) a ++; // инкремент, те. a = a + 1 e l s e a --; // декремент, те. a = a - Пример 2.5. Здесь ветвь else отсутствует f ( x > 5 ) a = Пример 2.6. Вложенный if: i f ( x < -1 ) a = 10; e l s e i f ( x >= 5) a = 20; e l s e a = Более компактное форматирование — 58 — i f ( x < -1 ) a = 10; e l s e i f ( x >= 5) a = 20; e l s e a = Можно вкладывать друг в друга произвольное число операторов Для проверки значения нужного бита переменной используются рассмотренные выше поразрядные логические операции. Например, приведённый ниже условный оператор будет выполнен, если й бит переменной имеет значение 1: |