Операции над числовыми данными целого типа




Над целочисленными данными (константами и переменными) в языках C, C++ можно выполнять обычные арифметические операции - сложение (x+y), вычитание (z-5), умножение (x1*x3) и деление (y/w). В отличие от языка Pascal здесь деление целочисленных операндов дает целочисленный результат. Например, 5/2=2. Для получения остатка от деления в C, C++ используется операция %, например, 5%2=1.

Целочисленные данные можно подвергать операции сдвига как влево (знак операции - <<), так и вправо (знак операции - >>) на заданное количество двоичных разрядов:

y=x<<3; // сдвиг влево на три двоичные разрядаz=y>>5; // сдвиг вправо на пять двоичных разрядов

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

#include <stdio.h>#include <conio.h>int main(){ int x=5, y=-5; unsigned z=0xFFFFFFFB; printf("x=%x y=%x z=%x",x,y,z); printf("\nx<<2=%x x>>2=%x",x<<2,x>>2); printf("\ny<<2=%x y>>2=%x",y<<2,y>>2); printf("\nz<<2=%x z>>2=%x",z<<2,z>>2); getch(); return 0;}//=== Результат работы ===x=5 y=fffffffb z=fffffffbx<<2=20 x>>2=1y<<2=ffffffec y>>2=fffffffez<<2=ffffffec z>>2=3ffffffe

Дело в том, что для чисел со знаком операция сдвига на n разрядов эквивалентна умножению на 2n при сдвиге влево или делению на 2n при сдвиге вправо. Поэтому для отрицательного операнда результат сдвига должен остаться отрицательным. С этой целью при сдвиге вправо производится размножение знакового разряда.

Над одноименными двоичными разрядами целочисленных операндов могут выполняться логические операции - логическое сложение (символ операции ' | '), логическое умножение (символ операции ' & '), исключающее ИЛИ (символ операции ' ^ ') и инвертирование (символ операции ' ~ '). Приведенная ниже программа иллюстрирует выполнение указанных операций над переменными x=5 (двоичный код 00...0101) и y=7 (двоичный код 00...0111).

#include <stdio.h>#include <conio.h>int main(){ int x=5, y=7; printf("x=%x y=%x",x,y); printf("\nx|y=%x x&y=%x",x|y,x&y); printf("\nx^y=%x ~x=%x",x^y,~x); getch(); return 0;}//=== Результат работы ===x=5 y=7x|y=7 x&y=5x^y=2 ~x=fffffffa

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

Функция abs(x) возвращает модуль своего аргумента. Аргументом функций atoi(s) и atol(s) является строка, представляющая запись целого числа. Каждая из этих функций преобразует символьную запись числа в соответствующий машинный формат (результат atoi имеет тип int, результат atol - тип long) и возвращает полученный результат. Довольно полезное преобразование выполняют функции itoa и ltoa. Первый их аргумент - числовое значение типа int или long. Вторым аргументом является строковый массив (или указатель на строку), куда записывается результат преобразования. А третий аргумент, значение которого находится в диапазоне от 2 до 36, определяет основание системы счисления, в которую преобразуется значение первого аргумента.

В ряде математических алгоритмов, использующих вероятностные методы (методы Монте-Карло), а чаще - в игровых программах активно используются различные датчики случайных чисел. Функция random(N) при каждом повторном обращении к ней выдает очередное случайное число из диапазона от 0 до N-1. Эти числа имеют равномерное распределение вероятностей, что можно трактовать следующим образом. Допустим, мы обратились к функции random(1000) 1000 раз. Можно утверждать, что среди полученных чисел почти все будут разными. Конечно, на практике это не совсем так, но вероятность того, что среди полученных чисел встретится много одинаковых, близка к нулю. Для игровых программ очень важно, чтобы при обращении к датчику случайных чисел каждый раз возникала непредсказуемая последовательность. С этой целью можно обратиться к функции randomize(), которая случайным образом возмущает начальное состояние программы, генерирующей случайные числа.

Продемонстрируем использование датчика случайных чисел на примере программы перемешивания колоды карт. Предположим, что для идентификации карт использованы целые числа в диапазоне от 0 до 35 (или до 51). Идея алгоритма перемешивания состоит в многократной генерации случайных чисел от 0 до 35 и перекладывания первой карты с k-той (k - очередное случайное число). Организуем пятикратное перемешивание, чтобы убедиться в том, что каждый раз колода оказывается в новом непредсказуемом состоянии.

#include <stdio.h>#include <stdlib.h>#include <conio.h> void mixer(char *b){ int j; char i,tmp; randomize(); for(j=0; j<10000; j++) { i=random(36); tmp=b[0]; b[0]=b[i]; b[i]=tmp; }} int main(){ char j,k,a[36]; printf("\nPlaying-cards before:\n"); for(k=0; k<36; k++) { a[k]=k; printf("%4d",a[k]); } for(j=0; j<5; j++) { mixer(a); printf("\nPlaying-cards after %d:\n",j); for(k=0; k<36; k++) printf("%4d",a[k]); } getch(); return 0;}//=== Результат работы ===Playing-cards before: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35Playing-cards after 0: 9 0 13 32 18 30 14 24 34 28 7 26 35 16 3 27 5 11 6 23 21 8 31 17 29 2 15 22 33 12 19 25 1 4 10 20Playing-cards after 1: 28 9 16 1 6 19 3 29 10 33 24 15 20 5 32 22 30 26 14 17 8 34 25 11 12 13 27 31 4 35 23 2 0 18 7 21Playing-cards after 2: 33 28 5 0 14 23 32 12 7 4 29 27 21 30 1 31 19 15 3 11 34 10 2 26 35 16 22 25 18 20 17 13 9 6 24 8Playing-cards after 3: 4 33 30 9 3 17 1 35 24 18 12 22 8 19 0 25 23 27 32 26 10 7 13 15 20 5 31 2 6 21 11 16 28 14 29 34Playing-cards after 4: 18 4 19 28 32 11 0 20 29 6 35 31 34 23 9 2 17 22 1 15 7 24 16 27 21 30 25 13 14 8 26 5 33 3 12 10


Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2019-04-04 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: