Как сделать отрицание в си

Добавил пользователь Владимир З.
Обновлено: 04.10.2024

Синтаксис оператора присвоения языка СИ имеет вид:
LValue = RValue;
LValue – это то куда будет записано значение. В роли такого объекта в СИ может выступать только переменная.
RValue – это то значение чего мы запишем в LValue. А в этой роли могут выступать такие объекты как:
переменная,
константа,
оператор вызова функции,
математическое или логическое выражение.
Примеры присвоений
int a, b, c;
double x, y;
a = 5; b = 4; c = a + b;
x = 5.0; y = exp(x);

Усовершенствованные операторы присвоений в СИ

В СИ присутствуют так называемые усовершенствованные операторы присвоения, выглядят они так:
LValue X= RValue; где X – это одна операция из набора: + - * / % ^ & | >. это является аналогией оператора присвоения:
LValue = LValue X RValue;
К примеру:
a += b; ≡ a = a + b;
В языке СИ все математические операции можно разделить на 2 группы:
1. математические операции для вещественных и целочисленных вычислений;
2. математические операции только для целочисленных вычислений.

К математическим операциям для вещественных и целочисленных вычислений языка СИ относят обычные арифметические операции:
сложения (+),
вычитания (-),
умножения (*), деления (/).

Соответствие типа результата от типов операндов
Тип первого операнда Тип второго операнда Тип результата
целый целый целый
целый вещественный вещественный
вещественный целый вещественный
вещественный вещественный вещественный

Особенности языка СИ

Рассмотрим одну из особенностей на примере:
int a,b;
double c;
a = 10;
b = 4;
c = a / b; // c будет равно 2, т.к выполняется операция не деления, а деления нацело или же:
double x = 1 / 3; // x будет равен 0, по той же причине что и в предыдущем примере

Операции для целочисленных вычислений

К операциям целочисленных вычислений относятся:
операция взятия остатка от деления,
побитовые операции,
операции сдвигов,
операции инкремента и декремента.
Операция взятия остатка от деления(mod) является бинарной операцией и в языке СИ обозначается символом процента (%). Пример вычисления:
int a = 10, b = 3, c;
c = a % b; // с будет равно 1

Побитовые операции в СИ

Вот таблица истинности для этих операций:
первый операнд второй операнд операция
и или исключающее или
0 0 0 0 0
1 0 0 1 1
0 1 0 1 1
1 1 1 1 0

Унарной побитовой операцией является операция отрицания, обозначаемая символом тильды (~). Пример:
unsigned char a = 10, b; //a: 00001010 = 10
b = ~a; //b: 11110101 = 245

Операции сдвига осуществляют побитовый сдвиг целого значения, указанного в первом операнде, вправо (символ >>) или влево (символ unsigned char a = 10, b, c; //a: 00001010 = 10
b = a > 1; //c: 00000101 = 5

Операции инкремента (знак ++) и декремента (знак --) являются унарными и осуществляют увеличение и уменьшение целого значения на единицу соответственно.
int a = 10, b, c;
b = ++a //пред- инкремент b == 11
c = a++; //пост- инкремент с == 11

В современных языках программирования (в том числе и языке СИ стандарта С99) данные операции могут использоваться и для вещественных значений. Пример:
double x = 12.5;
x++;
printf("%lf\n”,x); //вывод: 13.5

В языках программирования операции отношения (сравнения) являются бинарными операциями, осуществляющими сравнение двух операндов и возвращающие результат сравнения в виде логического значения. В языке СИ принято логические значения ИСТИНА и ЛОЖЬ интерпретировать посредством целочисленных значений:
0 – ЛОЖЬ, 1 – ИСТИНА.
Обозначение Название
> Больше
= Больше или равно
int a=5, b=4, c=10, x, y;
x = a > b; //x == 1
y = c == a; //y == 0

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


Примеры логических операций:
int a=1, b=0, c, d; //a – ИСТИНА, b – ЛОЖЬ
c = a || b; //c == 1
d = !b && a; //d == 1


Не определяется порядок, в котором вычисляются аргументы функции при ее вызове. Поэтому следующий оператор может дать различные результаты при трансляции разными компиляторами:
printf("%d %lf\n”, ++n, pow(2.0,n));
Результат будет зависеть от того, получает ли n приращение до или после вызова функции pow. Чтобы решить проблему достаточно записать так: n++;
printf("%d %lf\n”, n,pow(2.0,n));

1.Если какой-либо из операторов имеет тип long double, то и другой приводится к long double.
2.Иначе, если какой-либо из операторов имеет тип double, то и другой приводится к double.
3.Иначе, если какой-либо из операторов имеет тип float, то и другой приводится к float.
4.Иначе, для обоих операндов выполняется расширение целого типа; затем, если один из операндов имеет тип unsigned long int, то другой преобразуется в unsigned long int.
5.Иначе, если один из операндов имеет тип long int, а другой – unsigned int, то результат зависит от того, представляет ли long int все значения unsigned int; если это так, то операнд типа unsigned int
6.приводится к типу long int; если нет, то оба операнда преобразуются в unsigned long int.
7.Иначе, если один из операндов имеет тип long int, то и другой приводится к long int.
8.Иначе, оба операнда имеют тип int.

int a = 15, b = 2; double r = 0.0;
r = a / b; //r == 7.0
Оператор приведения типа: (тип)выражение.
r = (double)a / b; //Правильно
r = (double) (a / b); //Неправильно

int main(int argc, char *argv[])
<
double x,y;
printf("Введите значения: ");
scanf("%lf %lf”,&x,&y);
double max = (x > y) ? x : y;
printf("Максимальное значение: %lf\n",max);
return 0;
>

int main(int argc, char *argv[])
double x, y, z;
printf("Введите значения: ");
scanf("%lf %lf %lf",&x,&y,&z);
double max = (x > y) ? ((x > z) ? x : z): ((y > z) ? y :z);
printf("Максимальное значение: %lf\n",max);
return 0;
>

int main(int argc, char *argv[])
<
double a;
printf("Введите значение: ");
scanf("%lf",&a);
a *= (a *=a);
printf("Результат: %lf\n",a);
return 0;
>

int main(int argc, char *argv[])
double a,b,c;
printf("Введите коэффициенты A, B и С: ");
scanf("%lf %lf %lf",&a,&b,&c);
double d = b*b-4*a*c;
int n = (d 0.0)?2:1;
printf("Количество корней: %d\n",n);
return 0;
>

& - побитовое И
Можно назвать умножением(для простоты запоминания), соответственно - 0 умножить на 0 будет 0, 1 умножить на 0 будет 0, 1 умножить на 1 будет 1.
0101
&
0011
=
0001
С помощью этой операции, можно проверять состояние отдельных битов, для этого нужно иметь при себе битовые маски(определенный набор битов, которые используются для выбора отдельных битов, или нескольких битов ). Рассмотрим примеры.
Для того чтобы проверить четность числа, нам достаточно проверить самый первый бит, чему он равен, если 1 то число нечетное, если 0 значит четное,
dec binary

как было сказано, нас интересует первый бит, тот который крайний справа, все отстальные биты можно не рассматривать, значит нам нужно наше число(которе проверяем на четность) побитово умножить на маску, так как 7 из 8 битов нас не интересуют, то получаем такую вот маску - 00000001. Теперь это можно проверить на практике.
число 123 - нечетное, в битовом представлении это 01111011, умножаем на маску:
01111011
&
00000001

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

^ - исключающее ИЛИ (XOR)
Лучше никак не называть кроме как XOR :-) чтобы не вносить путаницу. Два одинаковых по значению бита, дают 0, два различных по значению дают 1
0101
^
0011
=
0110

>> - побитовый сдвиг вправо

> E2(на сколько)
Биты слева заполняются нулями. !НО! Если E1 имеет знаковый тип и отрицательное значение, то результат зависит от реализации этой операции процессором(implementation-defined), для процессоров Intel, при такой ситуации, биты слева могут заполняются единицами.

Теперь перейдем к примерам.

Установить нужный бит в 1

Очистить нужный бит(сбросить, установить в 0)

Инвертировать нужный бит (0 в 1, 1 в 0)

Тест нужного бита (установлен он в 0 или 1)

Подсчет количества единичных битов.
Для того чтобы подсчитать количество единичных битов можно использовать следующую операцию x&(x-1)
Суть этой операции в том что самый младший единичный бит устанавливается в 0, соответственно выполняя в цикле эту операцию над значением, можно подсчитать количество единичных битов, которое будет равно количеству итераций.
0b01001011 - количество единичных битов 4
считаем:
0b01001011 & (0b01001011 - 1) = 0b01001010
0b01001010 & (0b01001010 - 1) = 0b01001000
0b01001000 & (0b01001000 - 1) = 0b01000000
0b01000000 & (0b01000000 - 1) = 0b00000000

Обмен двух значений без использования временной переменной.
Все знают как обменять значения двух переменных с помощью временной переменной.
Но не все знают как это сделать без временной переменной :-), с помощью XOR, код ниже.

Один из алгоритмов генерации случайных чисел, разработанный Джорджом Марсаглием,
xorshift (больше примеров по ссылке)

Использование XOR также применяется в шифровании, ниже пример простого шифрования на основе XOR и ключа шифрования, его недостатком является то что зная часть исходных данных можно вычислить ключ, но такой прием используется как маленькая часть больших и сложных алгоритмов шифрования.
Если зашифрованную строку проксорить оригинальной то мы получим ключ :-)

XOR также може применяется для шифрования данных, к примеру данные храняться на 3-х дисках, первый хранит половину информации, второй вторую половину, третий результат XOR обеих данных первых двух дисков. Для расшифровки данных достаточно двух любых дисков.

Определить имеют ли два числа, противоположные знаки

Установить или сбросить биты по маске
Много интересных примеров также есть !здесь! (некоторые из которых присутствуют в этом посте.)

Логические операторы это специальные символы (или сочетания символов), которые изменяют или комбинируют логические значения типа Boolean — true и false. Их используют чтобы создавать сложные условия, например в циклах.

Логические операторы

Оператор НЕ (!, not)

Выражение вида !true равно false и наоборот. ! — унарный оператор (применяется к одному операнду), он помещается перед операндом.

Оператор И (&&, and)

Выражение вида a && b будет равно true только тогда, когда и а и b равны true.

Оператор ИЛИ (||, or)

Выражение a || b будет равно true, когда или a, или b (или оба) равен true.

Оператор исключающее ИЛИ (^, xor)

Оператор эквивалентности ==

Выражение a == b будет равно true, когда a и b имеют одинаковые значения.

Оператор неравенства !=

Выражение a != b будет равно true, когда a и b имеют разные значения.

Приоритет логических операторов

  1. Оператор эквивалентности — ==, оператор неравенства — !=.
  2. Оператор отрицания — !.
  3. Оператор И — &&.
  4. Оператор исключающее ИЛИ — ^.
  5. Оператор ИЛИ — ||.

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

Операции - это комбинации символов, определяющие действия по преобразованию значений.

В Си определены 5 арифметических операций: сложение (знак операции " + "), вычитание ( " - "), умножение ( " * ") , деление ( " / ") и взятие остатка от деления ( " % "). Приоритеты и работа операций обычные: умножение, деление и взятие остатка от деления равноправны между собой и старше, чем сложение и вычитание. Ассоциативность (порядок выполнения) арифметических операций принята слева направо.

Операция % определена только над целыми операндами, а результат операции деления зависит от типа операндов. Деление целых в Си дает всегда целое число, если же хотя бы один из операндов вещественный, результат также будет вещественным:

3 /2 // результат=1

3 ./2 // результат=1.5

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

Возможно объединение присваивания с другой операцией, используемое как сокращенная форма записи для присваивания, изменяющего значение переменной:

x +=3; // эквивалентно x = x +3;

p *= s ; // эквивалентно p = p * s ;

Присваивание также может быть составным, при этом цепочка вычислений выполняется справа налево:

Присваивание начального значения переменной (а также элементов массива) может быть выполнено непосредственно при описании:

Для распространенных операций инкремента (увеличения на 1) и декремента (уменьшения на 1) есть специальные обозначения ++ и -- соответственно:

i++; // эквивалентно i+=1; или i=i+1;

Операнд инкремента и декремента может иметь целый или вещественный тип или быть указателем.

Операции инкремента и декремента могут записываться как перед своим операндом (префиксная форма записи), так и после него (постфиксная запись). Для операции в префиксной форме операнд сначала изменяется, а затем его новое значение участвует в дальнейшем вычислении выражения. Для операции в постфиксной форме операнд изменяется после того, как его старое значение участвует в вычислении выражения:

printf ("\n%d",i++); // напечатает значение i = 3

printf ("\n%d",++i); // напечатает значение i = 4

Присваивание с приведением типа (тип)(выражение) использует заключенное в круглые скобки название типа, к которому нужно привести результат:

float f1 =4 ,f2 =3 ;

int a = (int)(f1/f2); //a=1

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

Логические операции в языке Си делятся на 2 класса. Во‑первых, это логические функции, служащие для объединения условий, во‑вторых, поразрядные логические операции, выполняемые над отдельными битами своих операндов. Операнды логических операций могут иметь целый, вещественный тип, либо быть указателями. Типы первого и второго операндов могут различаться. Сначала всегда вычисляется первый операнд; если его значения достаточно для определения результата операции, то второй операнд не вычисляется.

Логические оп е рации не выполняют каких‑либо преобразований по умолчанию. Вместо этого они вычисляют свои операнды и сравнивают их с нулем. Результатом логической операции является либо 0 , понимаемый как ложь, либо ненулевое значение (обычно 1 ), трактуемый как истина. Существенно то, что в языке Си нет специального логического типа данных и тип результата логической операции - целочисленный.

Логическая функция "И" (соответствует and в Паскале) обозначается как && , "ИЛИ" ( or ) как || , унарная функция отрицания ( not в Паскале ) записывается как ! перед своим операндом:

printf ("\nx не принадлежит [a,b]");

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

Как отмечено ранее, поразрядные логические операции выполняются над отдельными битами (разрядами) своих операндов. Имеется три бинарных и одна унарная поразрядная операция. Они описаны в табл. 3.1.

Читайте также: