Вопрос

How could I extract the absolute value of INT_MIN without overflowing? See this code for the problem:

#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): %d\n", abs(INT_MIN));

    return 0;
}

Spits out the following

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

I need this for a check if an int value is greater than zero.

As for this question being a duplicate of Why the absolute value of the max negative integer -2147483648 is still -2147483648?, I have to disagree, since this is a HOW, not a WHY question.

Это было полезно?

Решение

The %d conversion specifier in the format string of printf converts the corresponding argument to a signed decimal integer, which in this case, overflows for the int type. C standard specifically mentions that signed integer overflow is undefined behaviour. What you should do is to use %u in the format string. Also, you need to include the headers stdio.h and stdlib.h for the prototype of the functions printf and abs respectively.

#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;
}

This gives the output on my 32-bit machine:

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

Другие советы

How about

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

Or if your long is not longer than an int:

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

Or if you are prepared to accept that abs(INT_MIN) is always INT_MAX + 1:

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

There is no portable way to extract the absolute value of the most negative number as an integer. The ISO C standard says (§6.2.6.2¶2):

Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M ≤ N ).

Notice it uses ≤, not <.

Since the sign bit in 2's complement has the value −(2M), and each value bit has a value that is a power of two between 1 and 2M-1, there is no way an unsigned integer on implementations where M=N can represent 2N, it can only represent up to 2N-1 = 1+2+...+2N-1.

In C, only the int version exists for the function int abs(int j). You can use another function labs under the header stdlib.h. Its prototype: 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;
}

Casting into the next available greater integer type should do it. but you have to use the correspondant abs-variant (in this case llabs(...))

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

edit:

you can check what's the next greater type by comparing INT_MIN to LONG_MIN and LLONG_MIN. Maybe in your case a cast to long will already do it.

printf("labs(INT_MIN): %ld\n", labs((long int)INT_MIN));

Note that the explicit casts are in fact unnecessary as the function itself would cast the argument implicitly

First things first, you have to #include <math.h> to properly use the abs function.

Second thing is, if the only thing you want to achieve is to print the absolute value of the INT_MIN defined in limits.h, you can just print it out as an unsigned integer or as a long long integer, like this:

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

Since you want to have the absolute value, which most definitely will be unsigned, this should be alright.

If you don't want to include math.h, you can make it on your own like this:

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

If you want to use it for other purposes, then you can store the abs( INT_MIN ) value in unsigned int or long long int variables.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top