Абсолютное значение INT MIN [дубликат]


На этот вопрос уже есть ответ здесь:

Как я мог извлечь абсолютное значение INT_MIN без переполнения? Смотрите этот код для решения проблемы:

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

int main(void) {
    printf("INT_MAX: %dn", INT_MAX);
    printf("INT_MIN: %dn", INT_MIN);
    printf("abs(INT_MIN): %dn", abs(INT_MIN));

    return 0;
}

Выплевывает следующее

INT_MAX: 2147483647
INT_MIN: -2147483648
abs(INT_MIN): -2147483648

Мне это нужно для проверки, если значение int больше нуля.

Что касается этого вопроса, являющегося дубликатом , почему абсолютное значение максимального отрицательного целого числа -2147483648 все еще равно -2147483648?Я вынужден не согласиться, поскольку это вопрос "как", а не "почему".

6 9

6 ответов:

Спецификатор преобразования %d в строке формата printf преобразует соответствующий аргумент в знаковое десятичное целое число, которое в этом случае переполняется для типа int. Стандарт C специально упоминает, что переполнение целого числа со знаком является неопределенным поведением. То, что вы должны сделать, это использовать %u в строке формата. Также необходимо включить заголовки stdio.h и stdlib.h для прототипа функций printf и abs соответственно.

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

// This solves the issue of using the standard abs() function
unsigned int absu(int value) {
    return (value < 0) ? -((unsigned int)value) : (unsigned int)value;
}

int main(void) {
    printf("INT_MAX: %d\n", INT_MAX);
    printf("INT_MIN: %d\n", INT_MIN);
    printf("absu(INT_MIN): %u\n", absu(INT_MIN));

    return 0;
}

Это дает выход на мой 32-разрядная машина:

INT_MAX: 2147483647
INT_MIN: -2147483648
absu(INT_MIN): 2147483648

Как насчет

printf ("abs(INT_MIN) = %ld", -((long int) INT_MIN));

Или если ваш long не длиннее int:

printf ("abs(INT_MIN) = %lld", -((long long int) INT_MIN));

Или если вы готовы принять, что abs(INT_MIN) Всегда INT_MAX + 1:

printf ("abs(INT_MIN) = %u", ((unsigned int) INT_MAX ) + 1 );

Нет переносимого способа извлечь абсолютное значение самого отрицательного числа в виде целого числа. Стандарт ISO C гласит:(§6.2.6.2¶2):

Каждый бит, являющийся битом значения, должен иметь то же значение, что и тот же бит в объекте. представление соответствующего беззнакового типа (если в знаке имеется M бит значений тип и Н-тип unsigned, то m ≤ П ).

Обратите внимание, что он использует ≤, а не <.>

Так как знаковый бит в дополнении 2 имеет значение -(2М), и значение каждого бита имеет определенное значение, которое является степенью двух между 1 и 2м-1, нет возможности беззнаковое целое, на реализации, где м=н может представлять 2Н, он может только представлять до 2Н-1 = 1+2+...+2 N-1.

В C существует только версия int для функции int abs(int j). Вы можете использовать другую функцию labs под заголовком stdlib.h. Его прототип: long int labs(long int j);

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

int main(void) {
    printf("INT_MAX: %d\n", INT_MAX);
    printf("INT_MIN: %d\n", INT_MIN);
    printf("abs(INT_MIN): %ld\n", labs((long)INT_MIN));

    return 0;
}

Приведение к следующему доступному большему целочисленному типу должно сделать это. но вы должны использовать соответствующий АБС-вариант (в данном случае llabs(...))

printf("llabs(INT_MIN): %lld\n", llabs((long long int)INT_MIN));

Редактировать:

Вы можете проверить, что является следующим большим типом, сравнивая INT_MIN с LONG_MIN и LLONG_MIN. Может быть, в вашем случае приведение к long уже сделает это.

printf("labs(INT_MIN): %ld\n", labs((long int)INT_MIN));
Обратите внимание, что явные приведения на самом деле не нужны, так как сама функция будет приводить аргумент неявно

Во-первых, вы должны #include <math.h> правильно использовать функцию abs.

Во-вторых, если единственное, чего вы хотите достичь, - это вывести абсолютное значение INT_MIN, определенное в limits.h, Вы можете просто распечатать его как unsigned integer или как long long integer, например:
printf( "abs(INT_MIN): %u\n", abs( INT_MIN ) );     // %u for unsigned int
printf( "abs(INT_MIN): %lld\n", abs( INT_MIN ) );   // %lld for long long int

Поскольку вы хотите иметь абсолютное значение, которое наверняка будет без знака, это должно быть нормально.

Если вы не хотите включать math.h, вы можете сделать это самостоятельно, как это:

// ternary implementation of the function abs
printf( "abs(INT_MIN): %u\n", ( INT_MIN > 0 ) ? INT_MIN : -INT_MIN );

Если вы хотите использовать его для других целей, то вы можете хранить значение abs( INT_MIN ) в переменных unsigned int или long long int.