Какая арифметическая операция служит для получения остатка от деления
Перейти к содержимому

Какая арифметическая операция служит для получения остатка от деления

  • автор:

Mod и остаток — не одно и то же

Приготовьтесь, вас ждёт крайне педантичная статья, которая вполне может спасти вас на собеседовании или сэкономить несколько часов при вылавливании бага в продакшне!

Я сейчас активно работаю над вторым сезоном «Руководства для самозванца» и пишу о шифре RSA для SSH, который, очевидно, является самым загружаемым фрагментом кода в истории IT.

Хочется полностью разобраться в этой истории. Кто придумал этот шифр, как он работает, почему работает и будет ли работать в будущем. Сейчас я раскопал одну чертовски интересную историю. Я не криптоманьяк и вижу, как других буквально засасывает в эту область. Но мне это тоже интересно, потому что повсюду есть маленькие норки, а меня как сороку привлекают блестящие штучки в глубоких норках. Я также очень хорош в метафорах.

В любом случае: на прошлой неделе я узнал что-то странное и хочу поделиться: оказывается, mod и остаток от деления — не одно и то же. Действительно забавно то, что некоторые читатели при этих словах выпрыгивают со своих кресел и орут: «А ведь именно это я всегда пытался сказать вам и всем остальным!»

Позовите ребят из секты «mod не остаток»! Это для вас.

Что такое mod?

Я должен был изучить это, как и в прошлый раз, когда всплыла такая тема. Это одна из тех вещей, которые ты знаешь, но не запоминаешь. Когда вы применяете mod, то делите одно число на другое и берёте остаток. Итак: 5 mod 2 будет 1, потому что 5/2=2 с остатком 1.

Термин mod означает операцию modulo, с модулем 2 в данном случае. Большинство языков программирования используют % для обозначения такой операции: 5 % 2 = 1 .

Вот где мы попадаем в странную серую область.

Математика циферблата

Помню, как учил это в школе, а потом забыл. Существует тип математики, называемый «модульной арифметикой», которая имеет дело с циклическими структурами. Самый простой способ представить это — циферблат с циклом 12. Для математика циферблат — это mod 12 . Если хотите понять, можно ли равномерно разделить 253 часа на дни, то можете применить операцию 253 mod 24 , результатом будет 13, поэтому ответ «нет»! Мы можем ответить «да» только если результат 0.

Другой вопрос, который вы можете задать: «Если я выеду в 6 вечера, сколько времени будет по приезду через 16 часов?». Это будет 6 + 16 mod 12 , то есть 10.

Криптографы любят mod , потому что при использовании с действительно большими числами можно создать нечто, известное как «односторонние функции». Это специальные функции, которые позволяют легко вычислить что-то в одном направлении, но не в обратном.

Если я скажу вам, что 9 является результатом возведения в квадрат, вы можете легко определить, что на входе было 3. Перед вами весь процесс от начала до конца. Если я скажу, что 9 является результатом mod 29 , то будет сложнее понять, что на входе.

Криптографам нравится эта идея, потому что они могут использовать деление с остатком с гигантскими простыми числами для генерации криптографических ключей. Это совсем другая история: если хотите прочитать об этом, то можете купить книгу или, ещё лучше, поддержать мои усилия написать её.

Впрочем, не будем отклоняться от темы.

Остатки и математика циферблата

Теперь переходим к сути: modulo и простой остаток одинаковы, когда числа положительны, но отличаются в случае отрицательных чисел.

Рассмотрим такую задачу:

const x = 19 % 12; console.log(x);

Каково значение x ? Делим числа и получаем 7 как остаток от 12. Это верный ответ. Как насчет такого:

const y = 19 % -12; console.log(y);

Используя обычную математику, мы можем умножить -12 на -1, что даёт 12, и у нас по-прежнему остаётся 7, поэтому наш ответ снова 7.

JavaScript с этим согласен:

C# тоже согласен:

Google согласен с первым утверждением, но не согласен со вторым:

Ruby согласен с Google:

Во имя Дейкстры, что здесь происходит?

Вращение часов назад

Чтобы ответить на вопрос, следует понять разницу между остатком и modulo. Программисты объединяют эти операции, но не должны этого делать, потому что они дают одинаковый результат только в случае, если делитель (в нашем случае 12) положителен. Вы можете легко отправить баги в продакшн, если делитель отрицательный.

Но почему существует разница? Рассмотрим положительный делитель 19 mod 12 на часах:

Конечный результат 7. Мы это знаем и мы можем доказать математически. Но что насчёт 19 mod -12 ? Здесь нужно использовать другие часы:

Модуль равен -12, и мы не можем игнорировать или изменить его, умножив на -1, поскольку модульная арифметика так не работает. Единственный способ правильно рассчитать результат — переставить метки на часах так, чтобы мы двигались от -12 или вращали часы против часовой стрелки, что даёт тот же результат.

Почему не начать метки с -1, двигаясь к -2, и т.д.? Потому что в таком случае мы будем двигаться назад и постоянно уменьшать результат, пока не достигнем -12, и в этот момент сделаем прыжок +12, а modulo так не работает.

Это известная вещь

Прежде чем назвать меня сумасшедшим и начать гуглить тему: это известный факт. На самом деле MDN (Mozilla Developer Network) даже дошла до того, чтобы назвать % операцией «остатка» (remainder), а не modulo:

Оператор remainder возвращает остаток от деления одного операнда на другой. Он всегда принимает знак делимого.

Вот что Эрик Липперт, один из богов C#, говорит о modulo в C#:

Однако это совсем не то, что оператор % реально делает в C#. Оператор % не является каноническим оператором modulus, это оператор остатка.

А как на вашем языке?

Ну и что?

Могу понять, если вы дочитали досюда, а теперь чешете голову и задаётесь вопросом, стоит ли беспокоиться. Думаю, что стоит по двум причинам:

  1. Я представляю, как этот вопрос займёт меня врасплох на собеседовании.
  2. Я представляю, как этот попадёт в продакшн, а разработчики будут несколько часов выяснять, почему математика не работает.

Тест на тему: «Программирование на Pascal»

Время выполнения теста 15 минут, тест состоит из 3х частей по уровням сложности. Первый уровень A состоит из 10 вопросов с выбором ответа(в каждом задании только 1 верный ответ), второй уровень B состоит из 4 вопросов, где надо указать получившийся ответ и уровень С, где всего 1 вопрос – написание программы.

Уровень сложности А

1. Какой символ необходим для разделения операторов?

2. Какое имя объекта недопустимо в Pascal?

3. Выберите число относящееся к типу real:

4. Выберите верный символ или набор символов, который называется оператором присваивания

5. Каким словом обозначается оператор вывода в Pascal

6. Какая арифметическая операция служит для получения остатка от деления

7. Какая функция поможет посчитать квадрат от числа х?

8. Как выглядит логическая операция «дизъюнкция» в Pascal?

9. Выберите правильную запись выражения «А не равно 4»

10. Какое из ниже перечисленных утверждений верно?

а) If(f>2) then а:=3 еlse a:=5;

б) If(f>2) then а:=3; еlse a:=5;

в) If(f>2) then а=3; еlse a=5;

г) If(f>2) а:=3; еlse a:=5;

Уровень сложности В

11. Определите значение переменной С после выполнения алгоритма:

12. Запишите зна­че­ние переменной t, по­лу­чен­ное в ре­зуль­та­те работы сле­ду­ю­щей программы.

for k := 4 to 7 do

13. Определите, что будет на­пе­ча­та­но в ре­зуль­та­те работы сле­ду­ю­щей программы.

Var r, k: integer;

for k :=4 downto 1 do

14. В таб­ли­це D хра­нят­ся дан­ные о ко­ли­че­стве уче­ни­ков в клас­сах (D[1] — ко­ли­че­ство уче­ни­ков в пер­вом классе, D[2] — во вто­ром и т. д.). Определите, какое число будет на­пе­ча­та­но в ре­зуль­та­те ра­бо­ты сле­ду­ю­щей программы.

Var k, m: integer;

D: array[1..11] of integer;

Арифметические операторы (справочник по C#)

Следующие операторы выполняют арифметические операции с операндами числовых типов:

  • унарные — ++ (приращение), — (уменьшение), + (плюс) и — (минус);
  • бинарные — * (умножение), / (деление), % (остаток от деления), + (сложение) и — (вычитание).

Эти операторы поддерживаются всеми целочисленными типами и типами с плавающей запятой.

В случае целочисленных типов эти операторы (за исключением операторов ++ и — ) определяются для типов int , uint , long и ulong . Если операнды принадлежат к другим целочисленным типам ( sbyte , byte , short , ushort или char ), их значения преобразуются в тип int , который также является типом результата операции. Если операнды принадлежат к разным целочисленным типам или типам с плавающей запятой, их значения преобразуются в ближайший содержащий тип, если такой тип существует. Дополнительные сведения см. в разделе Числовые повышения уровня в статье Спецификации языка C#. Операторы ++ и — определяются для всех целочисленных числовых типов и числовых типов с плавающей запятой, а также типа char. Тип результата выражения сложного назначения является типом левого операнда.

Оператор инкремента ++

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

Оператор инкремента поддерживается в двух формах: постфиксный оператор инкремента ( x++ ) и префиксный оператор инкремента ( ++x ).

Постфиксный оператор приращения

Результатом x++ является значение x перед выполнением операции, как показано в следующем примере:

int i = 3; Console.WriteLine(i); // output: 3 Console.WriteLine(i++); // output: 3 Console.WriteLine(i); // output: 4 

Префиксный оператор инкремента

Результатом ++x является значение x после выполнения операции, как показано в следующем примере:

double a = 1.5; Console.WriteLine(a); // output: 1.5 Console.WriteLine(++a); // output: 2.5 Console.WriteLine(a); // output: 2.5 

Оператор декремента —

Унарный оператор декремента — уменьшает операнд на 1. Операндом должна быть переменная, свойство или индексатор.

Оператор декремента поддерживается в двух формах: постфиксный оператор декремента ( x— ) и префиксный оператор декремента ( —x ).

Постфиксный оператор уменьшения

Результатом x— является значение x перед выполнением операции, как показано в следующем примере:

int i = 3; Console.WriteLine(i); // output: 3 Console.WriteLine(i--); // output: 3 Console.WriteLine(i); // output: 2 

Префиксный оператор декремента

Результатом —x является значение x после выполнения операции, как показано в следующем примере:

double a = 1.5; Console.WriteLine(a); // output: 1.5 Console.WriteLine(--a); // output: 0.5 Console.WriteLine(a); // output: 0.5 

Операторы унарного плюса и минуса

Унарный оператор + возвращает значение полученного операнда. Унарный оператор — изменяет знак операнда на противоположный.

Console.WriteLine(+4); // output: 4 Console.WriteLine(-4); // output: -4 Console.WriteLine(-(-4)); // output: 4 uint a = 5; var b = -a; Console.WriteLine(b); // output: -5 Console.WriteLine(b.GetType()); // output: System.Int64 Console.WriteLine(-double.NaN); // output: NaN 

Тип ulong не поддерживает унарный оператор — .

Оператор умножения *

Оператор умножения * вычисляет произведение операндов:

Console.WriteLine(5 * 2); // output: 10 Console.WriteLine(0.5 * 2.5); // output: 1.25 Console.WriteLine(0.1m * 23.4m); // output: 2.34 

Оператор деления /

Оператор деления / делит левый операнд на правый.

Деление целых чисел

Для операндов цельночисленных типов результат оператора / является целочисленным типом, который равен частному двух операндов, округленному в сторону нуля:

Console.WriteLine(13 / 5); // output: 2 Console.WriteLine(-13 / 5); // output: -2 Console.WriteLine(13 / -5); // output: -2 Console.WriteLine(-13 / -5); // output: 2 

Чтобы получить частное двух операндов в виде числа с плавающей запятой, используйте тип float , double или decimal :

Console.WriteLine(13 / 5.0); // output: 2.6 int a = 13; int b = 5; Console.WriteLine((double)a / b); // output: 2.6 

Деление чисел с плавающей запятой

Для типов float , double и decimal результатом оператора / является частное двух операндов:

Console.WriteLine(16.8f / 4.1f); // output: 4.097561 Console.WriteLine(16.8d / 4.1d); // output: 4.09756097560976 Console.WriteLine(16.8m / 4.1m); // output: 4.0975609756097560975609756098 

Если один из операндов — это decimal , второй операнд не может быть ни float , ни double , так как ни float , ни double не преобразуется неявно в тип decimal . Необходимо явным образом преобразовать операнд float или double в тип decimal . Дополнительные сведения о числовых преобразованиях см. в разделе Встроенные числовые преобразования.

Оператор остатка %

Оператор остатка % вычисляет остаток от деления левого операнда на правый.

Целочисленный остаток

Для целочисленных операндов результатом a % b является значение, произведенное a — (a / b) * b . Знак ненулевого остатка такой же, как и у левого операнда, как показано в следующем примере:

Console.WriteLine(5 % 4); // output: 1 Console.WriteLine(5 % -4); // output: 1 Console.WriteLine(-5 % 4); // output: -1 Console.WriteLine(-5 % -4); // output: -1 

Используйте метод Math.DivRem для вычисления результатов как целочисленного деления, так и определения остатка.

Остаток с плавающей запятой

Для операндов типа float и double результатом x % y для конечных x и y будет значение z , так что:

  • знак z , если отлично от нуля, совпадает со знаком x ;
  • абсолютное значение z является значением, произведенным |x| — n * |y| , где n — это наибольшее возможное целое число, которое меньше или равно |x| / |y| , а |x| и |y| являются абсолютными значениями x и y , соответственно.

Этот метод вычисления остатка аналогичен тому, который использовался для целочисленных операндов, но отличается от спецификации IEEE 754. Если вам нужна операция вычисления остатка, которая соответствует спецификации IEEE 754, используйте метод Math.IEEERemainder.

Сведения о поведение оператора % в случае неконечных операндов см. в разделе Оператор остаткаспецификации языка C#.

Для операндов decimal оператор остатка % эквивалентен оператору остатка типа System.Decimal.

В следующем примере показано поведение оператора остатка для операндов с плавающей запятой:

Console.WriteLine(-5.2f % 2.0f); // output: -1.2 Console.WriteLine(5.9 % 3.1); // output: 2.8 Console.WriteLine(5.9m % 3.1m); // output: 2.8 

Оператор сложения +

Оператор сложения + вычисляет сумму своих операндов:

Console.WriteLine(5 + 4); // output: 9 Console.WriteLine(5 + 4.3); // output: 9.3 Console.WriteLine(5.1m + 4.2m); // output: 9.3 

Кроме того, оператор + можно использовать для объединения строк и делегатов. Дополнительные сведения см. в статье Операторы + и += .

Оператор вычитания —

Оператор вычитания — вычитает правый операнд из левого:

Console.WriteLine(47 - 3); // output: 44 Console.WriteLine(5 - 4.3); // output: 0.7 Console.WriteLine(7.5m - 2.3m); // output: 5.2 

Кроме того, оператор — можно использовать для удаления делегатов. Дополнительные сведения см. в статье Операторы — и -= .

Составное присваивание

Для бинарного оператора op выражение составного присваивания в форме

x op= y 
x = x op y 

за исключением того, что x вычисляется только один раз.

Следующий пример иллюстрирует использование составного присваивания с арифметическими операторами:

int a = 5; a += 9; Console.WriteLine(a); // output: 14 a -= 4; Console.WriteLine(a); // output: 10 a *= 2; Console.WriteLine(a); // output: 20 a /= 4; Console.WriteLine(a); // output: 5 a %= 3; Console.WriteLine(a); // output: 2 

Из-за восходящих приведений результат операции op может быть невозможно неявно преобразовать в тип T из x . В этом случае, если op является предопределенным оператором, и результат операции является явно преобразуемым в тип T x , выражение составного присваивания формы x op= y эквивалентно x = (T)(x op y) , за исключением того, что x вычисляется только один раз. В следующем примере продемонстрировано такое поведение.

byte a = 200; byte b = 100; var c = a + b; Console.WriteLine(c.GetType()); // output: System.Int32 Console.WriteLine(c); // output: 300 a += b; Console.WriteLine(a); // output: 44 

В предыдущем примере значение является результатом преобразования значения 44 300 в byte тип.

В контексте проверка переполнения проверка, приведенный выше пример вызывает исключениеOverflowException. Дополнительные сведения см. в разделе арифметического переполнения целочисленного числа.

Вы также можете использовать операторы += и -= для подписки и отмены подписки на события соответственно. Дополнительные сведения см. в разделе Практическое руководство. Подписка и отмена подписки на события.

Очередность и ассоциативность операторов

В следующем списке перечислены арифметические операторы в порядке убывания приоритета:

  • Постфиксный инкремент x++ и декремент x—
  • Префиксный инкремент ++x и декремент —x , унарные операторы + и —
  • Мультипликативные операторы * , / , и %
  • Аддитивные операторы + и —

Бинарные арифметические операторы имеют левую ассоциативность. То есть операторы с одинаковым приоритетом вычисляются в направлении слева направо.

Порядок вычисления, определяемый приоритетом и ассоциативностью операторов, можно изменить с помощью скобок ( () ).

Console.WriteLine(2 + 2 * 2); // output: 6 Console.WriteLine((2 + 2) * 2); // output: 8 Console.WriteLine(9 / 5 / 2); // output: 0 Console.WriteLine(9 / (5 / 2)); // output: 4 

Полный список операторов C#, упорядоченный по уровню приоритета, можно найти в разделе Приоритет операторов статьи Операторы C#.

Арифметическое переполнение и деление на нуль

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

Целочисленное арифметическое переполнение

Деление целого числа на ноль всегда вызывает исключение DivideByZeroException.

В случае целочисленного арифметического переполнения итоговое поведение определяется проверяемым или непроверяемым контекстом проверки переполнения:

  • Если в проверяемом контексте переполнение возникает в константном выражении, происходит ошибка времени компиляции. В противном случае, если операция производится во время выполнения, возникает исключение OverflowException.
  • В непроверяемом контексте результат усекается путем удаления старших разрядов, которые не помещаются в целевой тип данных.

Вместе с проверяемыми и непроверяемыми операторами можно использовать операторы checked и unchecked , чтобы управлять контекстом проверки переполнения, в котором вычисляется выражение:

int a = int.MaxValue; int b = 3; Console.WriteLine(unchecked(a + b)); // output: -2147483646 try < int d = checked(a + b); >catch(OverflowException) < Console.WriteLine($"Overflow occurred when adding to ."); > 

По умолчанию арифметические операции выполняются в непроверяемом контексте.

Арифметическое переполнение с плавающей запятой

Арифметические операции с типами float и double никогда не вызывают исключение. Результатом арифметических операций с этими типами может быть одно из специальных значений, представляющих бесконечность и объект, не являющийся числовым:

double a = 1.0 / 0.0; Console.WriteLine(a); // output: Infinity Console.WriteLine(double.IsInfinity(a)); // output: True Console.WriteLine(double.MaxValue + double.MaxValue); // output: Infinity double b = 0.0 / 0.0; Console.WriteLine(b); // output: NaN Console.WriteLine(double.IsNaN(b)); // output: True 

Для операндов типа decimal арифметическое переполнение всегда выдает исключение OverflowException, а деление на нуль — DivideByZeroException.

Ошибки округления

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

Console.WriteLine(.41f % .2f); // output: 0.00999999 double a = 0.1; double b = 3 * a; Console.WriteLine(b == 0.3); // output: False Console.WriteLine(b - 0.3); // output: 5.55111512312578E-17 decimal c = 1 / 3.0m; decimal d = 3 * c; Console.WriteLine(d == 1.0m); // output: False Console.WriteLine(d); // output: 0.9999999999999999999999999999 

См. заметки в справочной документации по System.Double, System.Single и System.Decimal.

Возможность перегрузки оператора

Определяемый пользователем тип может перегружать унарные ( ++ , — , + и — ) и бинарные ( * , / , % , + и — ) арифметические операторы. При перегрузке бинарного оператора соответствующий оператор составного присваивания также неявно перегружается. Явная перегрузка составного оператора присваивания для пользовательского типа невозможна.

Проверенные операторы, определяемые пользователем

Начиная с C# 11 при перегрузке арифметического оператора можно использовать ключевое слово checked , чтобы определить проверенную версию этого оператора. Следующий пример показывает, как это сделать:

public record struct Point(int X, int Y) < public static Point operator checked +(Point left, Point right) < checked < return new Point(left.X + right.X, left.Y + right.Y); >> public static Point operator +(Point left, Point right) < return new Point(left.X + right.X, left.Y + right.Y); >> 

При определении проверенного оператора следует также определить соответствующий оператор без модификатора checked . Проверенный оператор вызывается в проверенном контексте. Оператор без модификатора checked вызывается в непроверенном контексте. Если указать только оператора без модификатора checked , он будет вызываться как в контексте checked , так и в unchecked .

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

  • Проверенный оператор вызывает OverflowException.
  • Оператор без модификатора checked возвращает экземпляр, который представляет усеченный результат.

Сведения о разнице в поведении встроенных арифметических операторов см. в разделе Арифметическое переполнение и деление на ноль.

Модификатор checked можно использовать только при перегрузке следующих операторов:

  • Унарные операторы ++ , — и —
  • Бинарные операторы * , / , + и —
  • Операторы явного преобразования

Контекст проверки переполнения в теле проверенного оператора не изменяется при наличии модификатора checked . Контекст по умолчанию определяется значением параметра компилятора CheckForOverflowUnderflow. С помощью операторов checked и unchecked можно явно указать контекст проверки переполнения, как показано в примере в начале этого раздела.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

  • Постфиксные операторы инкремента и декремента
  • Префиксные операторы инкремента и декремента
  • Оператор унарного плюса
  • Оператор унарного минуса
  • Оператор умножения
  • Оператор деления
  • Оператор остатка
  • Оператор сложения
  • Оператор вычитания
  • Составное присваивание
  • Операторы checked и unchecked
  • Восходящие приведения числовых типов

См. также

  • Операторы и выражения C#
  • System.Math
  • System.MathF
  • Числовые значения в .NET

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Урок №39. Арифметические операторы

На этом уроке мы рассмотрим арифметические операторы и их использование в языке С++.

Оглавление:

  1. Унарные арифметические операторы
  2. Бинарные арифметические операторы
  3. Деление целых чисел и чисел типа с плавающей точкой
  4. Использование оператора static_cast в операциях деления
  5. Деление с остатком
  6. Отрицательные числа в операциях деления до C++11
  7. Арифметические операторы присваивания
  8. Где оператор возведения в степень?
  9. Тест

Унарные арифметические операторы

Унарные операторы — это операторы, которые применяются только к одному операнду. Существуют два унарных арифметических оператора: плюс ( + ) и минус ( − ).

Оператор Символ Пример Операция
Унарный плюс + +x Значение x
Унарный минус −x Отрицательное значение x

Унарный оператор + возвращает значение операнда. Другими словами, +5 = 5 или +х = х . Унарный плюс вам, скорее всего, не придется использовать. Его по большей части добавили в качестве симметрии с унарным оператором минус. Унарный оператор минус возвращает операнд, умноженный на −1 . Например, если х = 5 , то −х = −5 .

Оба этих оператора пишутся непосредственно перед самим операндом, без пробела ( −x , а не − x ).

Не следует путать унарный оператор минус с бинарным оператором вычитания, хоть они и используют один и тот же символ. Например, в выражении х = 5 − −3; , первый минус — это оператор вычитания, а второй — унарный минус.

Бинарные арифметические операторы

Бинарные операторы — это операторы, которые применяются к двум операндам (слева и справа). Существует 5 бинарных операторов.

Оператор Символ Пример Операция
Сложение + x + y x плюс y
Вычитание x − y x минус y
Умножение * x * y x умножить на y
Деление / x / y x разделить на y
Деление с остатком % x % y Остаток от деления x на y

Операторы сложения, вычитания и умножения работают так же, как и в обычной математике. А вот деление и деление с остатком рассмотрим детально.

Деление целых чисел и чисел типа с плавающей точкой

Оператор деления имеет два режима. Если оба операнда являются целыми числами, то оператор выполняет целочисленное деление. Т.е. любая дробь (больше/меньше) отбрасывается и возвращается целое значение без остатка, например, 7 / 4 = 1 .

Если один или оба операнда типа с плавающей точкой, то тогда будет выполняться деление типа с плавающей точкой. Здесь уже дробь присутствует. Например, выражения 7.0 / 3 = 2.333 , 7 / 3.0 = 2.333 или 7.0 / 3.0 = 2.333 имеют один и тот же результат.

Попытки деления на 0 (или на 0.0 ) станут причиной сбоя в вашей программе, и это правило не следует забывать!

Использование оператора static_cast в операциях деления

На уроке о символьном типе данных char мы уже использовали оператор static_cast для вывода ASCII-символов в виде целых чисел.

Аналогичным образом мы можем использовать static_cast для конвертации целого числа в число типа с плавающей точкой. Таким образом, вместо целочисленного деления выполнится деление типа с плавающей точкой. Например:

std :: cout << "double / int crayon-h"> << static_cast < double >( x ) / y << "\n" ;
std :: cout << "int / double crayon-h"> << x / static_cast < double >( y ) << "\n" ;
std :: cout << "double / double crayon-h"> << static_cast < double >( x ) / static_cast < double >( y ) << "\n" ;

Результат выполнения программы:

int / int = 1
double / int = 1.75
int / double = 1.75
double / double = 1.75

Деление с остатком

Оператор деления с остатком ( % ) работает только с целочисленными операндами и возвращает остаток от целочисленного деления. Например:

Пример №1: 7 / 4 = 1 с остатком 3 , таким образом, 7 % 4 = 3 .

Пример №2: 25 / 7 = 3 с остатком 4 , таким образом, 25 % 7 = 4 . Остаток составляет не дробь, а целое число.

Пример №3: 36 % 5 = 7 с остатком 1 . В числе 36 только 35 делится на 5 без остатка, поэтому 36 − 35 = 1 , 1 — это остаток и результат.

Данный оператор чаще всего используют для проверки деления без остатка одних чисел на другие. Если х % у == 0 , то х делится на у без остатка.

Например, мы хотим написать программу, которая выводит числа от 1 до 100 по 20 значений в каждой строке. Мы можем использовать оператор деления с остатком для создания разрыва строк. Несмотря на то, что мы еще не рассматривали цикл while, в следующей программе всё максимально просто и понятно:

// Переменная count хранит текущее число для вывода
int count = 1 ; // начинаем с 1
// Повторение операции (цикл) до тех пор, пока count не будет равен 100
while ( count <= 100 ) std :: cout << count << " " ; // вывод текущего числа // Если count делится на 20 без остатка, то вставляем разрыв строки и продолжаем с новой строки if ( count % 20 == 0 ) std :: cout << "\n" ; count = count + 1 ; // переходим к следующему числу > // конец while
> // конец main()

Результат выполнения программы:

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 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

О while мы еще поговорим на соответствующем уроке.

Отрицательные числа в операциях деления до C++11

До C++11, если любой из операндов целочисленного деления является отрицательным, то компилятор округляет результат самостоятельно! Например, результатом −5 / 2 может быть либо −3 , либо −2 . Однако большинство современных компиляторов округляют числа в сторону нуля (например, в −5 / 2 результатом будет −2 ). В спецификации C++11 определили, что компилятор должен всегда округлять к нулю (или, проще говоря, просто отбрасывать дробь).

Также до C++11, если один из операндов оператора деления с остатком является отрицательным, то результат может быть как положительным, так и отрицательным! Например, результатом −5 % 2 может быть как 1 , так и −1 . В спецификации C++11 решили сделать так, чтобы результат a % b был того же знака, что и значение а .

Арифметические операторы присваивания

Оператор Символ Пример Операция
Присваивание = x = y Присваиваем значение y переменной x
Сложение с присваиванием += x += y Добавляем y к x
Вычитание с присваиванием −= x −= y Вычитаем y из x
Умножение с присваиванием *= x *= y Умножаем x на y
Деление с присваиванием /= x /= y Делим x на y
Деление с остатком и с присваиванием %= x %= y Присваиваем остаток от деления x на y переменной x

До этого момента, когда нам нужно было добавить число 5 к определенной переменной, мы делали следующее:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *