Как портативно узнать min (INT_MAX, abs (INT_MIN))?

Как я могу портативно узнать самый маленький из INT_MAX и абс (INT_MIN)? (Это математическое абсолютное значение INT_MINне призыв к abs функция).

Это должно быть так же, как INT_MAX в большинстве систем, но я ищу более портативный способ.

30

Решение

В то время как типичный ценность INT_MIN -2147483648, а типичный ценность INT_MAX 2147483647, это не гарантируется стандартом. TL; DR: значение, которое вы ищете INT_MAX в соответствующей реализации. Но расчета min(INT_MAX, abs(INT_MIN)) не переносимый


Возможные значения INT_MIN а также INT_MAX

INT_MIN а также INT_MAX определены в Приложении E (Пределы реализации) 1 (стандарт C, C ++ наследует этот материал):

Содержание заголовка приведено ниже, в алфавитном порядке.
порядок. Указанные минимальные величины должны быть заменены
определяемые реализацией величины с тем же знаком. Значения должны
все должны быть константными выражениями, подходящими для использования в предварительной обработке #if
директивы. Компоненты описаны далее в 5.2.4.2.1.

[…]

#define INT_MAX +32767

#define INT_MIN -32767

[…]

Стандарт требует тип int быть целочисленным типом, который может представлять диапазон [INT_MIN, INT_MAX] (раздел 5.2.4.2.1.).

Тогда 6.2.6.2. (Целочисленные типы, опять же часть стандарта C), вступает в игру и еще более ограничивает это тем, что мы знаем как два или один дополняют:

Для целочисленных типов со знаком биты представления объекта должны быть разделены на три
группы: биты значения, биты заполнения и бит знака. Там не должно быть никаких битов заполнения;
знаковый символ не должен иметь никаких битов заполнения. Должен быть ровно один знаковый бит.
Каждый бит, который является битом значения, должен иметь то же значение, что и тот же бит в объекте
представление соответствующего типа без знака (если в знаке есть M битов значения
введите и N в беззнаковом типе, тогда M ≤ N). Если бит знака равен нулю, он не должен влиять на результирующее значение. Если знаковый бит равен единице, значение должно быть изменено в одном из
следующие способы:

— соответствующее значение со знаковым битом 0 обнуляется (знак и величина);

— бит знака имеет значение — (2M) (дополнение к двум);

— знаковый бит имеет значение — (2M — 1) (дополнение).

Раздел 6.2.6.2. Также очень важно связать представление значения целочисленных типов со знаком с представлением значения его беззнаковых братьев и сестер.

Это означает, что вы либо получите диапазон [-(2^n - 1), (2^n - 1)] или же [-2^n, (2^n - 1)], где n является типично 15 или 31

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

Теперь для второго: операции со знаковыми целочисленными типами, которые приводят к значению, которое находится за пределами диапазона [INT_MIN, INT_MAX], поведение не определено. Это явно предписано в C ++ пунктом 5/4:

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

Для C 6.5 / 5 предлагает очень похожий отрывок:

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

Так что же произойдет, если значение INT_MIN бывает меньше, чем негатив INT_MAX (например, -32768 и 32767 соответственно)? расчета -(INT_MIN) будет неопределенным, так же, как INT_MAX + 1,

Таким образом, мы должны избегать вычисления значения, которое может не находиться в диапазоне [INT_MIN, INT_MAX], Счастливый, INT_MAX + INT_MIN всегда в этом диапазоне, так как INT_MAX является строго положительным значением и INT_MIN строго отрицательное значение. следовательно INT_MIN < INT_MAX + INT_MIN < INT_MAX,

Теперь мы можем проверить, INT_MAX + INT_MIN равно, меньше или больше 0.

`INT_MAX + INT_MIN`  |  value of -INT_MIN    | value of -INT_MAX
------------------------------------------------------------------
< 0         |  undefined            | -INT_MAX
= 0         |  INT_MAX = -INT_MIN   | -INT_MAX = INT_MIN
> 0         |  cannot occur according to 6.2.6.2. of the C standard

Следовательно, чтобы определить минимум INT_MAX а также -INT_MIN (в математическом смысле) достаточно следующего кода:

if ( INT_MAX + INT_MIN == 0 )
{
return INT_MAX; // or -INT_MIN, it doesn't matter
}
else if ( INT_MAX + INT_MIN < 0 )
{
return INT_MAX; // INT_MAX is smaller, -INT_MIN cannot be represented.
}
else // ( INT_MAX + INT_MIN > 0 )
{
return -INT_MIN; // -INT_MIN is actually smaller than INT_MAX, may not occur in a conforming implementation.
}

Или, чтобы упростить:

return (INT_MAX + INT_MIN <= 0) ? INT_MAX : -INT_MIN;

Значения в троичном операторе будут оцениваться только при необходимости. Следовательно, -INT_MIN либо оставляется без оценки (поэтому не может генерировать UB), либо является четко определенным значением.

Или, если вы хотите утверждение:

assert(INT_MAX + INT_MIN <= 0);
return INT_MAX;

Или, если вы хотите это во время компиляции:

static_assert(INT_MAX + INT_MIN <= 0, "non-conforming implementation");
return INT_MAX;

Правильное получение целочисленных операций (т. Е. Если правильность имеет значение)

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

В зависимости от архитектуры могут быть другие параметры для обеспечения корректности, такие как опция gcc -ftrapv,

22

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

INT_MAX + INT_MIN < 0 ? INT_MAX : -INT_MIN

Отредактировано, чтобы добавить объяснение: Конечно, проблема в том, что -INT_MIN или же abs(INT_MIN) будет неопределенным, если -INT_MIN слишком большой, чтобы поместиться в int, Поэтому нам нужен способ проверить, так ли это на самом деле. Состояние INT_MAX + INT_MIN < 0 проверяет ли -INT_MIN больше, чем INT_MAX, Если это так, то INT_MAX является меньшим из двух абсолютных значений. Если нет то INT_MAX больше двух абсолютных значений, и -INT_MIN это правильный ответ.

10

В С99 и выше, INT_MAX,

Quot спецификации:

Для целочисленных типов со знаком биты представления объекта должны быть разделены на три
группы: биты значения, биты заполнения и бит знака. Там не должно быть никаких битов заполнения;
знаковый символ не должен иметь никаких битов заполнения. Должен быть ровно один знаковый бит.
Каждый бит, который является битом значения, должен иметь то же значение, что и тот же бит в объекте
представление соответствующего типа без знака (если в знаке есть M битов значения
введите и N в беззнаковом типе, тогда M ≤ N). Если знаковый бит равен нулю, он не должен влиять
результирующее значение. Если знаковый бит равен единице, значение должно быть изменено в одном из
следующие способы:

  • соответствующее значение со знаком бит 0 обнуляется (знак и величина);
  • знаковый бит имеет значение — (2 ^ M) (дополнение до двух);
  • знаковый бит имеет значение — (2 ^ M — 1) (дополнение).

(Раздел 6.2.6.2 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)

7

-INT_MAX представима как int насколько я знаю, на всех диалектах C и C ++. Следовательно:

-INT_MAX <= INT_MIN ? -INT_MIN : INT_MAX
1

В большинстве систем abs (INT_MIN) не определена. Например, на типичных 32-битных компьютерах INT_MAX = 2 ^ 31 — 1, INT_MIN = — 2 ^ 31 и abs (INT_MIN) не могут быть 2 ^ 31.

0

abs(INT_MIN) вызовет неопределенное поведение. Стандарт говорит

7.22.6.1 abs, labs а также llabs функции:

abs, labs, а также llabs функции вычисляют абсолютное значение целого числа j, Если результат не может быть представлен, поведение не определено.

Попробуйте это вместо этого:
Перерабатывать INT_MIN в unsignrd int, Поскольку -ve числа не могут быть представлены как unsigned int, INT_MAX будет преобразован в UINT_MAX + 1 + INT_MIN,

#include <stdio.h>
#include <stdlib.h>

unsigned min(unsigned a, unsigned b)
{
return a < b ? a : b;
}

int main(void)
{
printf("%u\n", min(INT_MAX, INT_MIN));
}
0
По вопросам рекламы [email protected]