Вычитание между подписанным и неподписанным с последующим делением

Следующие результаты приводят меня в замешательство:

int i1 = 20-80u;    // -60
int i2 = 20-80;     // -60
int i3 =(20-80u)/2; // 2147483618
int i4 =(20-80)/2;  // -30
int i5 =i1/2;       // -30
  1. i3 кажется, рассчитывается как (20u-80u)/2, вместо (20-80u)/2
  2. предположительно i3 такой же как i5,

24

Решение

IIRC, арифметическая операция между подписанным и неподписанным int приведет к неподписанному результату.

Таким образом, 20 - 80u производит неподписанный результат, эквивалентный -60: если unsigned int 32-битный тип, результат 4294967236.

Кстати, присвоение этого i1 производит от реализации результат, потому что число слишком велико, чтобы соответствовать. Получение -60 типично, но не гарантировано.

13

Другие решения

int i1 = 20-80u;    // -60

Это тонкие демоны! Операнды разные, поэтому необходимо преобразование. Оба операнда преобразуются в общий тип ( unsigned int, в этом случае). Результат, который будет большим unsigned int значение (на 60 меньше, чем UINT_MAX + 1 если мои расчеты верны) будут преобразованы в int прежде чем он хранится в i1, Поскольку это значение выходит за пределы диапазона intрезультат будет определен реализацией, может быть представлением ловушки и, следовательно, может вызвать неопределенное поведение при попытке его использования. Тем не менее, в вашем случае это по совпадению конвертируется в -60,


int i3 =(20-80u)/2; // 2147483618

Продолжая с первого примера, я думаю, что результат 20-80u будет на 60 меньше, чем UINT_MAX + 1, Если UINT_MAX 4294967295 (общее значение для UINT_MAX), это будет означать 20-80u является 4294967236… а также 4294967236 / 2 2147483618.


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

10

Бинарные арифметические операторы будут выполнять обычные арифметические преобразования на их операнды, чтобы привести их к общему типу.

В случае i1, i3 а также i5 общий тип будет без знака int и поэтому результат также будет без знака int. Числа без знака будут переноситься с помощью арифметики по модулю, поэтому вычитание немного большего значения без знака приведет к числу, близкому к целому числу без знака, которое не может быть представлено целым числом.

Так что в случае i1 мы получаем преобразование, определяемое реализацией, поскольку значение не может быть представлено. В случае i3 деление на 2 возвращает значение без знака обратно в диапазон int, и в результате мы получаем большое значение int со знаком после преобразования.

Соответствующие разделы из проекта стандарта C ++ следующие. Раздел 5.7 [Expr.add]:

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

Обычные арифметические преобразования рассматриваются в разделе 5 и это говорит:

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

[…]
  • В противном случае, если операнд с целым типом без знака имеет ранг больше или равен
    ранг типа другого операнда, операнд со знаком целого типа должен быть преобразован в
    тип операнда с целым типом без знака.

и для преобразования из значения, которое не может быть представлено для подписанного типа, раздел 4.7 [Conv.integral]:

Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и
ширина битового поля); в противном случае значение определяется реализацией.

и для целых чисел без знака подчиняется модулю арифметического раздела 3.9.1 [Basic.fundamental]:

Целые числа без знака должны подчиняться законам арифметики по модулю 2n, где n — количество битов в значении
представление этого конкретного размера целого числа.

3
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector