Главная страница » Что такое унарный минус

Что такое унарный минус

  • автор:

C++. Унарный минус и беззнаковый тип

Привет, Хабр! Меня зовут Владимир, я работаю в VK Карты. Хочу рассказать про случай, который недавно произошёл у нас в подразделении. Он кажется достаточно типичным и может быть интересен другим программистам.

Нам, программистам на C++, не привыкать, что даже самый безобидный код может таить в себе сюрпризы. Рассмотрим пример:

Он полон сюрпризов! Каких? Короткий ответ: значение signed_offset не определено стандартом и зависит от реализации. Но это далеко не все неожиданности в этом коде. Статья как раз о них.

Результат, возвращаемый унарным минусом

Давайте сначала разберемся с тем, что возвращает -width . Это может прозвучать неожиданно, но тип, возвращаемый -width , это uint32_t . И это не опечатка. То есть если унарный минус применить к неотрицательному числу, то в результате получим опять же неотрицательное число. Давайте разберёмся, как такое могло получиться и чему будет равен результат -width .

Если выполнить такой код:

Как мы выяснили выше, -width вернёт значение 4 294 967 289 типа uint32_t . А оно не поместится в int32_t . Соответственно, значение signed_offset будет не определено. Отмечу, что согласно стандарту это допустимая запись, не приводящая к неопределенному поведению. То есть код допустим, но значение в signed_offset после его исполнения может быть любым.

Если скомпилировать и запустить этот пример, то с большой долей вероятности в signed_offset окажется -7. Так реагирует Clang 13.1.6 на MacOS. Но это реакция на переполнение знакового целого числа. А с точки зрения стандарта в signed_offset может быть любое значение.

Переполнение знаковых и беззнаковых типов

Отмечу, что стандарт по-разному относится к переполнению знаковых и беззнаковых типов. При присвоении слишком большого значения знаковому типу мы получаем поведение, зависящее от реализации. Этот случай мы подробно рассмотрели выше. При присвоении слишком большого значения беззнаковому типу мы получим вполне определённое и гарантированное стандартом поведение, согласно разделу 7.8.2. Правило такое: если мы хотим присвоить число big_number переменной unsigned_offset беззнакового типа some_unsigned_type, то результатом этой операции будет число big_number по модулю 2 n , где n — количество бит, необходимое для хранения типа some_unsigned_type . Звучит запутано, но на самом деле тут всё предельно просто. Достаточно взглянуть на пример:

unsigned_offset будет равно 7, потому что размер uint32_t — 32 бита. 2 32 равно 4 294 967 296, а 4 294 967 296 + 4 294 967 296 по модулю 4 294 967 296 будет равно 0. Выходит результат 7.

Выводы и рекомендации

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

Во всех рассуждениях я преимущественно писал про uint32_t и int32_t . Однако эти рассуждения верны соответственно для всех знаковых и беззнаковых типов.

Ссылки

Хочу кое-что уточнить. То что я писал выше относится к стандарту C++17. В C++20 приняли «two’s complement». Это раздел 6.8.1, параграф 3. То есть код из начала статьи:

должен всегда работать одинаково в C++20, и signed_offset должно быть -7. В C++17 значение signed_offset не определено.

Базовые операторы, математика

Многие операторы знакомы нам ещё со школы: сложение + , умножение * , вычитание — и так далее.

В этой главе мы начнём с простых операторов, а потом сконцентрируемся на специфических для JavaScript аспектах, которые не проходят в школьном курсе арифметики.

Термины: «унарный», «бинарный», «операнд»

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

Операнд – то, к чему применяется оператор. Например, в умножении 5 * 2 есть два операнда: левый операнд равен 5 , а правый операнд равен 2 . Иногда их называют «аргументами» вместо «операндов».

Унарным называется оператор, который применяется к одному операнду. Например, оператор унарный минус "-" меняет знак числа на противоположный:

Бинарным называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:

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

Математика

Поддерживаются следующие математические операторы:

  • Сложение + ,
  • Вычитание — ,
  • Умножение * ,
  • Деление / ,
  • Взятие остатка от деления % ,
  • Возведение в степень ** .

Первые четыре оператора очевидны, а про % и ** стоит сказать несколько слов.

Взятие остатка %

Оператор взятия остатка % , несмотря на обозначение, никакого отношения к процентам не имеет.

Результат a % b – это остаток от целочисленного деления a на b .

Возведение в степень **

Оператор возведения в степень a ** b возводит a в степень b .

В школьной математике мы записываем это как a b .

Математически, оператор работает и для нецелых чисел. Например, квадратный корень является возведением в степень 1/2 :

Сложение строк при помощи бинарного +

Давайте рассмотрим специальные возможности операторов JavaScript, которые выходят за рамки школьной арифметики.

Обычно при помощи плюса ‘+’ складывают числа.

Но если бинарный оператор ‘+’ применить к строкам, то он их объединяет в одну:

Обратите внимание, если хотя бы один операнд является строкой, то второй будет также преобразован в строку.

Как видите, не важно, первый или второй операнд является строкой.

Вот пример посложнее:

Здесь операторы работают один за другим. Первый + складывает два числа и возвращает 4 , затем следующий + объединяет результат со строкой, производя действие 4 + ‘1’ = ’41’ .

Сложение и преобразование строк — это особенность бинарного плюса + . Другие арифметические операторы работают только с числами и всегда преобразуют операнды в числа.

Например, вычитание и деление:

Приведение к числу, унарный +

Плюс + существует в двух формах: бинарной, которую мы использовали выше, и унарной.

Унарный, то есть применённый к одному значению, плюс + ничего не делает с числами. Но если операнд не число, унарный плюс преобразует его в число.

На самом деле это то же самое, что и Number(. ) , только короче.

Необходимость преобразовывать строки в числа возникает очень часто. Например, обычно значения полей HTML-формы — это строки. А что, если их нужно, к примеру, сложить?

Бинарный плюс сложит их как строки:

Поэтому используем унарный плюс, чтобы преобразовать к числу:

С точки зрения математика, такое изобилие плюсов выглядит странным. Но с точки зрения программиста тут нет ничего особенного: сначала выполнятся унарные плюсы, которые приведут строки к числам, а затем бинарный ‘+’ их сложит.

Почему унарные плюсы выполнились до бинарного сложения? Как мы сейчас увидим, дело в их приоритете.

Приоритет операторов

В том случае, если в выражении есть несколько операторов – порядок их выполнения определяется приоритетом, или, другими словами, существует определённый порядок выполнения операторов.

Из школы мы знаем, что умножение в выражении 1 + 2 * 2 выполнится раньше сложения. Это как раз и есть «приоритет». Говорят, что умножение имеет более высокий приоритет, чем сложение.

Скобки важнее, чем приоритет, так что, если мы не удовлетворены порядком по умолчанию, мы можем использовать их, чтобы изменить приоритет. Например, написать (1 + 2) * 2 .

В JavaScript много операторов. Каждый оператор имеет соответствующий номер приоритета. Тот, у кого это число больше, – выполнится раньше. Если приоритет одинаковый, то порядок выполнения – слева направо.

Отрывок из таблицы приоритетов (нет необходимости всё запоминать, обратите внимание, что приоритет унарных операторов выше, чем соответствующих бинарных):

Приоритет Название Обозначение
15 унарный плюс +
15 унарный минус
14 возведение в степень **
13 умножение *
13 деление /
12 сложение +
12 вычитание
2 присваивание =

Так как «унарный плюс» имеет приоритет 15 , который выше, чем 12 у «сложения» (бинарный плюс), то в выражении "+apples + +oranges" сначала выполнятся унарные плюсы, а затем сложение.

Присваивание

Давайте отметим, что в таблице приоритетов также есть оператор присваивания = . У него один из самых низких приоритетов: 2 .

Именно поэтому, когда переменной что-либо присваивают, например, x = 2 * 2 + 1 , то сначала выполнится арифметика, а уже затем произойдёт присваивание = с сохранением результата в x .

Присваивание = возвращает значение

Тот факт, что = является оператором, а не «магической» конструкцией языка, имеет интересные последствия.

Большинство операторов в JavaScript возвращают значение. Для некоторых это очевидно, например сложение + или умножение * . Но и оператор присваивания не является исключением.

Вызов x = value записывает value в x и возвращает его.

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

В примере выше результатом (a = b + 1) будет значение, которое присваивается переменной a (то есть 3 ). Потом оно используется для дальнейших вычислений.

Забавное применение присваивания, не так ли? Нам нужно понимать, как это работает, потому что иногда это можно увидеть в JavaScript-библиотеках.

Однако писать самим в таком стиле не рекомендуется. Такие трюки не сделают ваш код более понятным или читабельным.

Присваивание по цепочке

Рассмотрим ещё одну интересную возможность: цепочку присваиваний.

Такое присваивание работает справа налево. Сначала вычисляется самое правое выражение 2 + 2 , и затем результат присваивается переменным слева: c , b и a . В конце у всех переменных будет одно значение.

Опять-таки, чтобы код читался легче, лучше разделять подобные конструкции на несколько строчек:

Польза от такого стиля особенно ощущается при быстром просмотре кода.

Сокращённая арифметика с присваиванием

Часто нужно применить оператор к переменной и сохранить результат в ней же.

Name already in use

javascript-tutorial-ru / 1-js / 2-first-steps / 8-operators / article.md

  • Go to file T
  • Go to line L
  • Copy path
  • Copy permalink
  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

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

Несколько операторов мы знаем со школы — это обычные сложение + , умножение * , вычитание и так далее.

В этой главе мы сконцентрируемся на операторах, которые в курсе математики не проходят, и на их особенностях в JavaScript.

Термины: «унарный», «бинарный», «операнд»

У операторов есть своя терминология, которая используется во всех языках программирования.

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

Операнд — то, к чему применяется оператор. Например: 5 * 2 — оператор умножения с левым и правым операндами. Другое название: «аргумент оператора».

Унарным называется оператор, который применяется к одному операнду. Например, оператор унарный минус «-» меняет знак числа на противоположный:

Бинарным называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:

Сложение строк, бинарный +

Обычно при помощи плюса ‘+’ складывают числа.

Но если бинарный оператор ‘+’ применить к строкам, то он их объединяет в одну:

Иначе говорят, что «плюс производит конкатенацию (сложение) строк».

Если хотя бы один аргумент является строкой, то второй будет также преобразован к строке!

Причем не важно, справа или слева находится операнд-строка, в любом случае нестроковый аргумент будет преобразован. Например:

Это приведение к строке — особенность исключительно бинарного оператора «+» .

Остальные арифметические операторы работают только с числами и всегда приводят аргументы к числу.

Преобразование к числу, унарный плюс +

Унарный, то есть применённый к одному значению, плюс ничего не делает с числами:

Как видно, плюс ничего не изменил в выражениях. Результат — такой же, как и без него.

Тем не менее, он широко применяется, так как его «побочный эффект» — преобразование значения в число.

Например, когда мы получаем значения из HTML-полей или от пользователя, то они обычно в форме строк.

А что, если их нужно, к примеру, сложить? Бинарный плюс сложит их как строки:

Поэтому используем унарный плюс, чтобы преобразовать к числу:

С точки зрения математики такое изобилие плюсов может показаться странным. С точки зрения программирования — никаких разночтений: сначала выполнятся унарные плюсы, приведут строки к числам, а затем — бинарный ‘+’ их сложит.

Почему унарные плюсы выполнились до бинарного сложения? Как мы сейчас увидим, дело в их приоритете.

В том случае, если в выражении есть несколько операторов — порядок их выполнения определяется приоритетом.

Из школы мы знаем, что умножение в выражении 2 * 2 + 1 выполнится раньше сложения, т.к. его приоритет выше, а скобки явно задают порядок выполнения. Но в JavaScript — гораздо больше операторов, поэтому существует целая таблица приоритетов.

Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число больше — выполнится раньше. Если приоритет одинаковый, то порядок выполнения — слева направо.

Отрывок из таблицы:

Приоритет Название Обозначение
. . .
15 унарный плюс +
15 унарный минус
14 умножение *
14 деление /
13 сложение +
13 вычитание
. . .
3 присваивание =
. . .

Так как «унарный плюс» имеет приоритет 15 , выше, чем 13 у обычного «сложения», то в выражении +apples + +oranges сначала сработали плюсы у apples и oranges , а затем уже обычное сложение.

Обратим внимание, в таблице приоритетов также есть оператор присваивания = .

У него — один из самых низких приоритетов: 3 .

Именно поэтому, когда переменную чему-либо присваивают, например, x = 2 * 2 + 1 сначала выполнится арифметика, а уже затем — произойдёт присваивание = .

Возможно присваивание по цепочке:

Такое присваивание работает справа-налево, то есть сначала вычислятся самое правое выражение 2+2 , присвоится в c , затем выполнится b = c и, наконец, a = b .

««smart header =\» возвращает значение» Все операторы возвращают значение. Вызов `x = выражение` не является исключением.

Он записывает выражение в x , а затем возвращает его. Благодаря этому присваивание можно использовать как часть более сложного выражения:

В примере выше результатом (a = b + 1) является значение, которое записывается в a (т.е. 3 ). Оно используется для вычисления c .

Забавное применение присваивания, не так ли?

Знать, как это работает — стоит обязательно, а вот писать самому — только если вы уверены, что это сделает код более читаемым и понятным.

Побитовые операторы рассматривают аргументы как 32-разрядные целые числа и работают на уровне их внутреннего двоичного представления.

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

Поддерживаются следующие побитовые операторы:

  • AND(и) ( & )
  • OR(или) ( | )
  • XOR(побитовое исключающее или) ( ^ )
  • NOT(не) (

Они используются редко, поэтому вынесены в отдельную главу info:bitwise-operators.

Сокращённая арифметика с присваиванием

Часто нужно применить оператор к переменной и сохранить результат в ней же, например:

Эту запись можно укоротить при помощи совмещённых операторов, вот так:

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

Один из самых необычных операторов — запятая ‘,’ .

Его можно вызвать явным образом, например:

Запятая позволяет перечислять выражения, разделяя их запятой ‘,’ . Каждое из них — вычисляется и отбрасывается, за исключением последнего, которое возвращается.

Запятая — единственный оператор, приоритет которого ниже присваивания. В выражении a = (5,6) для явного задания приоритета использованы скобки, иначе оператор ‘=’ выполнился бы до запятой ‘,’ , получилось бы (a=5), 6 .

Зачем же нужен такой странный оператор, который отбрасывает значения всех перечисленных выражений, кроме последнего?

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

Такие трюки используются во многих JavaScript-фреймворках для укорачивания кода.

Arithmetic operators

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

bitwise NOT

Overflows

Беззнаковая целочисленная арифметика всегда выполняется по модулю 2n
где n — количество битов в этом конкретном целом числе. Например , для unsigned int , добавляя один к UINT_MAX дает ​0​ , и вычитая одно из ​0​ дает UINT_MAX .

Когда переполняется целочисленная арифметическая операция со знаком (результат не помещается в тип результата), поведение не определено: оно может переноситься в соответствии с правилами представления (как правило, с дополнением 2), оно может перехватываться на некоторых платформах или из-за компилятора параметры (например, -ftrapv в GCC и Clang) или могут быть полностью оптимизированы компилятором .

Floating-point environment

Если для параметра #pragma STDC FENV_ACCESS задано значение ON , все арифметические операторы с плавающей запятой подчиняются текущему направлению округления с плавающей запятой и сообщают об арифметических ошибках с плавающей запятой, как указано в math_errhandling , кроме случаев, когда используется статический инициализатор (в этом случае исключения с плавающей запятой являются не поднят и режим округления до ближайшего).

Floating-point contraction

Если для #pragma STDC FP_CONTRACT не установлено значение OFF , вся арифметика с плавающей запятой может выполняться так, как если бы промежуточные результаты имели бесконечный диапазон и точность, то есть оптимизации, которые исключают ошибки округления и исключения с плавающей запятой, которые будут наблюдаться, если выражение было оценено именно так, как написано. Например, позволяет реализовать (x*y) + z с помощью одной объединенной инструкции процессора с многократным сложением или оптимизировать a = x*x*x*x; как tmp = x*x; a = tmp*tmp .

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

Unary arithmetic

Выражения унарных арифметических операторов имеют форму.

+ expression (1)
— expression (2)
expression выражение любого арифметического типа

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

  • унарный плюс возвращает стоимость после рекламы
  • унарный минус возвращает отрицательную величину после повышения (за исключением того,что отрицательная величина NaN-это другая NaN)

Тип выражения — это тип после повышения, а категория значения — не lvalue.

Notes

Унарный минус вызывает неопределенное поведение из-за переполнения целых чисел со INT_MIN при применении к INT_MIN , LONG_MIN или LLONG_MIN на типовых (дополнение 2) платформах.

В C++ унарный оператор + также может использоваться с другими встроенными типами, такими как массивы и функции, но не в C.

Additive operators

Выражения бинарных аддитивных арифметических операторов имеют форму.

lhs + rhs (1)
lhs — rhs (2)
  • оба имеют арифметические типы , в том числе сложные и мнимые
  • один является указателем на полный тип объекта,другой имеет целочисленный тип
  • оба имеют арифметические типы , в том числе сложные и мнимые
  • lhs имеет указатель на полный тип объекта,rhs имеет целочисленный тип
  • оба являются указателями на полные объекты совместимых типов, игнорируя квалификаторы
арифметическое сложение и вычитание

Если оба операнда имеют арифметические типы , то.

  • сначала выполняются обычные арифметические преобразования
  • затем значения операндов после преобразований складываются или вычитаются в соответствии с обычными правилами математики (для вычитания из lhs вычитается rhs),за исключением того,что
    • если один операнд-NaN,результат-NaN.
    • бесконечность минус бесконечность равна NaN и FE_INVALID повышается
    • бесконечность плюс отрицательная бесконечность равна NaN, а FE_INVALID повышается

    Сложные и мнимые сложения и вычитания определяются следующим образом (обратите внимание,что тип результата является мнимым,если оба операнда являются мнимыми,и сложным,если один операнд является реальным,а другой мнимым,как указано в обычных арифметических превращениях):

    + или — u iv u + iv
    x x ± u x ± iv (х ± и) ± iv
    iy ±у + у i(y ± v) ± и + я (у ± v)
    х+г (х ± и) + iy x + i(y ± v) (х ± и) + я (у ± v)
    Pointer arithmetic
    • Если указатель P указывает на элемент массива с индексом I , то
      • P+N и N+P — указатели, которые указывают на элемент того же массива с индексом I+N
      • P-N — указатель, указывающий на элемент того же массива с индексом I-N

      Поведение определяется только в том случае,если и исходный указатель,и указатель результата указывают на элементы одного и того же массива или на один и тот же конец этого массива.Обратите внимание,что выполнение p-1 при наведении указателя p на первый элемент массива является неопределенным поведением и может не сработать на некоторых платформах.

      • Если указатель P1 указывает на элемент массива с индексом I (или один после конца) и P2 указывает на элемент того же массива с индексом J (или один после конца), то
        • P1-P2 имеет значение, равное I-J , и тип ptrdiff_t (который представляет собой целочисленный тип со знаком, обычно вдвое меньше размера самого большого объекта, который может быть объявлен)

        Поведение определяется только в том случае, если результат помещается в ptrdiff_t .

        Для целей арифметики с указателями,указатель на объект,не являющийся элементом какого-либо массива,рассматривается как указатель на первый элемент массива размера 1.

        Multiplicative operators

        Двоичные выражения мультипликативных арифметических операторов имеют форму.

        lhs * rhs (1)
        lhs / rhs (2)
        lhs % rhs (3)
        • Сначала выполняются обычные арифметические преобразования . Затем.
        Multiplication

        Двоичный оператор*выполняет умножение своих операндов (после обычных арифметических преобразований),следуя обычным арифметическим определениям,за исключением этого.

        • если один операнд-NaN,результат-NaN.
        • умножение бесконечности на ноль дает NaN и FE_INVALID повышается
        • умножение бесконечности на ненулевое дает бесконечность (даже для сложных аргументов)

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

        * u iv u + iv
        x xu i(xv) (xu) + i(xv)
        iy i(yu) −yv (−yv) + я (ю)
        х+г (Сюй) + я (ю) (−yv) + я (xv) special rules

        Помимо обработки бесконечности, сложное умножение не может переполнять промежуточные результаты, за исключением случаев, когда #pragma STDC CX_LIMITED_RANGE установлено в ON , и в этом случае значение может быть вычислено, как если бы (x+iy)×(u+iv) = (xu -yv)+i(yu+xv), поскольку программист берет на себя ответственность за ограничение диапазона операндов и работу с бесконечностями.

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

        Division

        Двоичный оператор/делит первый операнд на второй (после обычных арифметических преобразований),следуя обычным определениям арифметики,за исключением этого.

        • когда тип после обычных арифметических приведений является целочисленным,в результате получается алгебраический коэффициент (а не дробь),округленный в направлении,определяемом реализацией(до C99),усеченный до нуля(начиная с C99)
        • если один операнд-NaN,результат-NaN.
        • если первый операнд представляет собой комплексную бесконечность, а второй операнд конечен, то результатом оператора / является комплексная бесконечность
        • если первый операнд конечен, а второй операнд представляет собой комплексную бесконечность, то результатом оператора / является нуль

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

        / u iv
        x x/u i(−x/v)
        iy i(y/u) y/v
        х+г (х / у) + я (у / у) (у/v) + я(-х/v)

        Помимо бесконечной обработки, сложное деление не может переполнять промежуточные результаты, за исключением случаев, когда для #pragma STDC CX_LIMITED_RANGE установлено значение ON , и в этом случае значение может быть вычислено, как если бы (x + iy) / (u + iv) = [( Xu + уу) + I (ю-XV)] / (и2
        +v2
        ), поскольку программист берет на себя ответственность за ограничение диапазона операндов и работу с бесконечностями.

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

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

        • Деление ненулевого числа на ±0,0 дает правильно подписанную бесконечность, а FE_DIVBYZERO повышается .
        • Деление 0.0 на 0.0 дает NaN и FE_INVALID повышается
        Remainder

        Двоичный оператор % дает остаток деления первого операнда на второй (после обычных арифметических преобразований).

        Знак остатка определяется таким образом, что если частное a/b представимо в типе результата, то (a/b)*b + a%b == a .

        Если второй операнд равен нулю,поведение не определено.

        Если частное a/b не представимо в типе результата, поведение a/b и a%b не определено (это означает, что INT_MIN%-1 не определен в системах дополнения 2).

        Примечание: оператор остатка не работает с типами с плавающей запятой, библиотечная функция fmod обеспечивает эту функциональность.

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

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