Correct way to take absolute value of INT_MIN - c

I want to perform some arithmetic in unsigned, and need to take absolute value of negative int, something like
do_some_arithmetic_in_unsigned_mode(int some_signed_value)
{
unsigned int magnitude;
int negative;
if(some_signed_value<0) {
magnitude = 0 - some_signed_value;
negative = 1;
} else {
magnitude = some_signed_value;
negative = 0;
}
...snip...
}
But INT_MIN might be problematic, 0 - INT_MIN is UB if performed in signed arithmetic.
What is a standard/robust/safe/efficient way to do this in C?
EDIT:
If we know we are in 2-complement, maybe implicit cast and explicit bit ops would be standard? if possible, I'd like to avoid this assumption.
do_some_arithmetic_in_unsigned_mode(int some_signed_value)
{
unsigned int magnitude=some_signed_value;
int negative=some_signed_value<0;
if (negative) {
magnitude = (~magnitude) + 1;
}
...snip...
}

Conversion from signed to unsigned is well-defined: You get the corresponding representative modulo 2N. Therefore, the following will give you the correct absolute value of n:
int n = /* ... */;
unsigned int abs_n = n < 0 ? UINT_MAX - ((unsigned int)(n)) + 1U
: (unsigned int)(n);
Update: As #aka.nice suggests, we can actually replace UINT_MAX + 1U by 0U:
unsigned int abs_n = n < 0 ? -((unsigned int)(n))
: +((unsigned int)(n));

In the negative case, take some_signed_value+1. Negate it (this is safe because it can't be INT_MIN). Convert to unsigned. Then add one;

You can always test for >= -INT_MAX, this is always well defined. The only case is interesting for you is if INT_MIN < -INT_MAX and that some_signed_value == INT_MIN. You'd have to test that case separately.

I want to perform some arithmetic in unsigned, and need to take absolute value of negative int, ...
To handle pedantic cases:
The |SOME_INT_MIN|1 has some special cases:
1. Non-two's complement
Ones' complement and sign-magnitude are rarely seen these days.
SOME_INT_MIN == -SOME_INT_MAX and some_abs(some_int) is well defined. This is the easy case.
#if INT_MIN == -INT_MAX
some_abs(x); // use matching abs, labs, llabs, imaxabs
#endif
2. SOME_INT_MAX == SOME_UINT_MAX, 2's complement
C allows the max of the signed and unsigned version of an integer type to be the same. This is rarely seen these days.
2 approaches:
1) use a wider integer type, if it exist.
#if -INTMAX_MAX <= SOME_INT_MIN
imaxabs((intmax_t)x)
#endif
2) Use wide(st) floating-point (FP) type.
Conversion to a wide FP will work for SOME_INT_MIN (2's complement) as that value is a -(power-of-2). For other large negatives, the cast may lose precision for a wide integer and not so wide long double. E.g. 64-bit long long and 64-bit long double.
fabsl(x); // see restriction above.
3. SOME_INT_MAX < SOME_UINT_MAX
This is the common case well handle by #Kerrek SB's answer. The below also handles case 1.
x < 0 ? -((unsigned) x) : ((unsigned) x);
Higher Level Alternative
In cases when code is doing .... + abs(x), a well defined alternative is to subtract the negative absolute value: .... - nabs(x). Or as in abs(x) < 100, use nabs > -100.
// This is always well defined.
int nabs(int x) {
return (x < 0) x : -x;
}
1 SOME_INT implies int, long, long long or intmax_t.

static unsigned absolute(int x)
{
if (INT_MIN == x) {
/* Avoid tricky arithmetic overflow possibilities */
return ((unsigned) -(INT_MIN + 1)) + 1U;
} else if (x < 0) {
return -x;
} else {
return x;
}
}

Related

How to check that a value fits in a type without invoking undefined behaviour?

I am looking to check if a double value can be represented as an int (or the same for any pair of floating point an integer types). This is a simple way to do it:
double x = ...;
int i = x; // potentially undefined behaviour
if ((double) i != x) {
// not representable
}
However, it invokes undefined behaviour on the marked line, and triggers UBSan (which some will complain about).
Questions:
Is this method considered acceptable in general?
Is there a reasonably simple way to do it without invoking undefined behaviour?
Clarifications, as requested:
The situation I am facing right now involves conversion from double to various integer types (int, long, long long) in C. However, I have encountered similar situations before, thus I am interested in answers both for float -> integer and integer -> float conversions.
Examples of how the conversion may fail:
Float -> integer conversion may fail is the value is not a whole number, e.g. 3.5.
The source value may be out of the range of the target type (larger or small than max and min representable values). For example 1.23e100.
The source values may be +-Inf or NaN, NaN being tricky as any comparison with it returns false.
Integer -> float conversion may fail when the float type does not have enough precision. For example, typical double have 52 binary digits compared to 63 digits in a 64-bit integer type. For example, on a typical 64-bit system, (long) (double) ((1L << 53) + 1L).
I do understand that 1L << 53 (as opposed to (1L << 53) + 1) is technically exactly representable as a double, and that the code I proposed would accept this conversion, even though it probably shouldn't be allowed.
Anything I didn't think of?
Create range limits exactly as FP types
The "trick" is to form the limits without loosing precision.
Let us consider float to int.
Conversion of float to int is valid (for example with 32-bit 2's complement int) for -2,147,483,648.9999... to 2,147,483,647.9999... or nearly INT_MIN -1 to INT_MAX + 1.
We can take advantage that integer_MAX is always a power-of-2 - 1 and integer_MIN is -(power-of-2) (for common 2's complement).
Avoid the limit of FP_INT_MIN_minus_1 as it may/may not be exactly encodable as a FP.
// Form FP limits of "INT_MAX plus 1" and "INT_MIN"
#define FLOAT_INT_MAX_P1 ((INT_MAX/2 + 1)*2.0f)
#define FLOAT_INT_MIN ((float) INT_MIN)
if (f < FLOAT_INT_MAX_P1 && f - FLOAT_INT_MIN > -1.0f) {
// Within range.
Use modff() to detect a fraction if desired.
}
More pedantic code would use !isnan(f) and consider non-2's complement encoding.
Using known limits and floating-point number validity. Check what's inside limits.h header.
You can write something like this:
#include <limits.h>
#include <math.h>
// Of course, constants used are specific to "int" type... There is others for other types.
if ((isnormal(x)) && (x>=INT_MIN) && (x<=INT_MAX) && (round(x)==x))
// Safe assignation from double to int.
i = (int)x ;
else
// Handle error/overflow here.
ERROR(.....) ;
Code relies on lazy boolean evaluation, obviously.
Please refer to IEEE 754 representation of floating point numbers in Memory
https://en.wikipedia.org/wiki/IEEE_754
Take double as an example:
Sign bit: 1 bit
Exponent: 11 bits
Fraction: 52 bits
There are three special values to point out here:
If the exponent is 0 and the fractional part of the mantissa is 0, the number is ±0
If the exponent is 2047 and the fractional part of the mantissa is 0, the number is ±∞
If the exponent is 2047 and the fractional part of the mantissa is non-zero, the number is NaN.
This is an example of convert from double to int on 64-bit, just for reference
#include <stdint.h>
#define EXPBITS 11
#define FRACTIONBITS 52
#define GENMASK(n) (((uint64_t)1 << (n)) - 1)
#define EXPBIAS GENMASK(EXPBITS - 1)
#define SIGNMASK (~GENMASK(FRACTIONBITS + EXPBITS))
#define EXPMASK (GENMASK(EXPBITS) << FRACTIONBITS)
#define FRACTIONMASK GENMASK(FRACTIONBITS)
int double_to_int(double src, int *dst)
{
union {
double d;
uint64_t i;
} y;
int exp;
int sign;
int maxbits;
uint64_t fraction;
y.d = src;
sign = (y.i & SIGNMASK) ? 1 : 0;
exp = (y.i & EXPMASK) >> FRACTIONBITS;
fraction = (y.i & FRACTIONMASK);
// 0
if (fraction == 0 && exp == 0) {
*dst = 0;
return 0;
}
exp -= EXPBIAS;
// not a whole number
if (exp < 0)
return -1;
// out of the range of int
maxbits = sizeof(*dst) * 8 - 1;
if (exp >= maxbits && !(exp == maxbits && sign && fraction == 0))
return -2;
// not a whole number
if (fraction & GENMASK(FRACTIONBITS - exp))
return -3;
// convert to int
*dst = src;
return 0;
}

Why is `x - y <= x` true, when x=0x80000000, y = 1(32-bit complement)? [duplicate]

This question already has answers here:
Detecting signed overflow in C/C++
(13 answers)
Closed 1 year ago.
I want to know if x - y overflows.
Below is my code.
#include <stdio.h>
/* Determine whether arguments can be subtracted without overflow */
int tsub_ok(int x, int y)
{
return (y <= 0 && x - y >= x) || (y >= 0 && x - y <= x);
}
int main()
{
printf("0x80000000 - 1 : %d\n", tsub_ok(0x80000000, 1));
}
Why can't I get the result I expect?
You can't check for overflow of signed integers by performing the offending operation and seeing if the result wraps around.
First, the value 0x80000000 passed to the function is outside the range of a 32 bit int. So it undergoes an implementation defined conversion. On most systems that use 2's compliment, this will result in the value with that representation which is -2147483648 which also happens to be the value of INT_MIN.
Then you attempt to execute x - y which results in signed integer overflow which triggers undefined behavior, giving you an unexpected result.
The proper way to handle this is to perform some algebra to ensure the overflow does not happen.
If x and y have the same sign then subtracting won't overflow.
If the signs differ and x is positive, one might naively try this:
INT_MAX >= x - y
But this could overflow. Instead change it to the mathematically equivalent:
INT_MAX + y >= x
Because y is negative, INT_MAX + y doesn't overflow.
A similar check can be done when x is negative with INT_MIN. The full check:
if (x>=0 && y>=0) {
return 1;
} else if (x<=0 && y<=0) {
return 1;
} else if (x>=0 && INT_MAX + y >= x) {
return 1;
} else if (x<0 && INT_MIN + y <= x) {
return 1;
} else {
return 0;
}
Yes, x - y overflows.
We assume int and unsigned int are 32 bits in the C implementation you are using, as indicated in the title, and that two’s complement is used for int. Then the range of values for int is −231 to +231−1.
In tsub_ok(0x80000000, 1), the constant 0x80000000 has the value 231, and its type is unsigned int since it will not fit in an int. Then this value is passed to tsub_ok. Since the first parameter of tsub_ok has type int, the value is converted to int.
By C 2018 6.3.1.3 3, the conversion is implementation-defined. Many C implementations “wrap” the value modulo 232. Assuming your C implementation does this, the result of converting 231 to int is −231.
Then, inside the function, x - y is −231 − 1, and the result of that overflows the int type. The C standard does not define the behavior of the program when signed integer overflow occurs, and so any test that relies on comparing x - y when it may overflow is not supported by the C standard.
Here an int is 32 bits. This means it has a total range of 2^32 possible values. Converting this to hex, that's a max of 0xFFFFFFFF(when unsigned), but not signed. A signed int will have a max hex value of 0x7FFFFFFF. Thus, you cannot store 0x80000000 in an int here and have everything work.
In computer programming, signed and unsigned numbers are represented only as sequences of bits. Bit 31 is the sign bit for a 32-bit signed int, hence the highest 32-bit int you can store is 0x7FFFFFFF, hence the overflow with 0x80000000 as signed int.
Remember, a signed int is an integer that can be both positive and negative. This is as opposed to an unsigned int, which can only be used to hold a positive integer.
What you are trying to do is, you are trying a signed int variable hold an unsigned value - which causes the overflow.
For more info check Signed number representations or refer any beginner level digital number systems and programming book.

converting from signed int to unsigned int without casting

int isNegative(int x) {
return ((unsigned) x)>> 31;
}
I'm writing a function that takes 32 bits and returns 1 if x<0, and 0 otherwise. How do I convert a signed int to an unsigned int without casting.
OP has different implied questions
a function that takes 32 bits and returns 1 if x<0, and 0 otherwise.
int isNegative(int x) {
return x < 0;
}
// or maybe return bool/_Bool
bool isNegative(int x) {
return x < 0;
}
// or pedantically
int isNegative(int_least32_t x) {
return x < 0;
}
// or pedantically and nearly universally portable,
int isNegative(int32_t x) {
return x < 0;
}
converting from signed int to unsigned int without casting (and)
How do I convert a signed int to an unsigned int without casting.
Simply assign the value
int i;
unsigned u = i;
Attempting to use >> to combined these two risk implementation defined behavior and should be avoided unless compelling reasons are given.
EXAMPLE An example of implementation-defined behavior is the propagation of the high-order bit when a signed integer is shifted right. C11§3.4.2 2
In this case you don't need to. If you get rid of the cast, right shifting retains the sign bit.
Assuming int is 32 bit, removing the cast results in -1 for negative numbers and 0 for nonnegative numbers. While the actual return value differs for the nonnegative case, in a Boolean context it will work as you expect.
Your question is to write a function that takes 32 bits and returns 1 if x < 0
int isNegative(int x) {
return x < 0;
}
This will work no matter what the size of int and does not invoke any type conversions. I suppose you have over-thought this problem.
There is a variety of operations that perform automatic type conversions, among them assignments, arithmetic operations under certain conditions, and function calls (conversion of certain argument values).
Thus, you could achieve conversion of (signed) int arguments to unsigned int simply by declaring that to be the parameter type:
int isNegative(unsigned x) {
return x >> 31;
}
Admittedly, however, that function interface could be a little confusing. You might therefore prefer to do this:
int isNegative(int x) {
unsigned ux = x;
return x >> 31;
}
However, I don't think either of those is as clear as your original version, with its cast. Type conversion is the entire purpose of a cast, and when conversion is what you need (and all that you need), a cast is the right tool for the job.
Of course, I do overall prefer the even simpler family of approaches suggested by #chux.

Why is a modulo operation returning an unexpected value

Why is the following code printing 255?
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint8_t i = 0;
i = (i - 1) % 16;
printf("i: %d\n", i);
return 0;
}
I assumed 15, although i - 1 evaluates to an integer.
Because of integer promotions in the C standard. Briefly: any type "smaller" than int is converted to int before usage. You cannot avoid this in general.
So what goes on: i is promoted to int. The expression is evaluated as int (the constants you use are int, too). The modulus is -1. This is then converted to uint8_t: 255 by the assignment.
For printf then i is integer-promoted to int (again): (int)255. However, this does no harm.
Note that in C89, for a < 0, a % b is not necessarily negative. It was implementation-defined and could have been 15. However, since C99, -1 % 16 is guaranteed to be -1 as the division has to yield the algebraic quotient.
If you want to make sure the modulus gives a positive result, you have to evaluate the whole expression unsigned by casting i:
i = ((unsigned)i - 1) % 16;
Recommendation: Enable compiler warnings. At least the conversion for the assignment should give a truncation warning.
This is because -1 % n would return -1 and NOT n - 1 1. Since i in this case is unsigned 8 bit int, it becomes 255.
1 See this question for more details on how modulo for negative integers works in C/C++.
This works (displays 15) with Microsoft C compiler (no stdint.h, so I used a typedef):
#include <stdio.h>
typedef unsigned char uint8_t;
int main(void) {
uint8_t i = 0;
i = (uint8_t)(i - 1) % 16;
printf("i: %d\n", i);
return 0;
}
The reason for the 255 is because (i - 1) is promoted to integer, and the integer division used for % in C rounds towards zero instead of negative infinity (rounding towards negative infinity is the way it's done in math, science, and other programming languages). So for C % is zero or has the same sign as the dividend (in this case -1%16 == -1), while in math modulo is zero or has the same sign as the divisor.

Why does it seem that INT_MIN and INT_MAX are out of range for type int?

When I use the INT_MAX and INT_MIN constants I get -2147483648 ... 2147483647.
But when I try to compute the maximum and minimum values for ints using this function:
static int computeInt(void)
{
int myInt = 0;
int min = 0;
int max = 32;
for (int i = min; i < max; i++)
{
myInt = myInt + pow(2, i);
}
myInt = myInt / 2;
return myInt;
}
I don't get the same number. I think the technical for what happens is that myInt overflows.
Thanks!
Yes, you have an overflow because the range for int is from -2^31 to 2^31 - 1 and you try to compute the sum of powers of 2 from 0 to 31. Your final value is the result of: (2^0 + 2^1 + 2^3 + ... + 2^31) / 2 which is obviously greater than 2^31 - 1
Your assumption is right. Your int overflows, because you keep adding to it. I'm not sure why you're using a loop, when the max int is simply 2^31-1 or pow(2,31)-1.
Using a loop you could do:
for (int i = min; i < max; i++) {
myInt = myInt * 2;
}
myInt = myInt - 1;
(Note that this loop also results in a temporary overflow. After the last iteration myInt will be -2147483648, but subtracting one will result in 2147483647)
It isn't possible to detect the maximum signed integer reliably through arithmetic in this way because as soon as the integer exceeds INT_MAX the result is undefined (it could simply crash).
You can however work out the maximum unsigned integer, as this is guaranteed to wrap around back to 0, i.e. UINT_MAX + 1 is guaranteed to be 0. Similarly, unsigned int a = -1 will equal UINT_MAX.
Since a signed int and unsigned int are guaranteed to use the same amount of storage and alignment, you could divide the calculated UINT_MAX by 2 to get INT_MAX. Therefore:
unsigned int maxint = -1;
maxint /= 2;
As stated in the previous answers and comments, you have an overflow (even when assuming sizeof(int) = 4.
If you want to compute "manually" these constants, you could simply do this :
int myInt = (((unsigned int)(-1)) >> 1);
int myIntMin = -myInt - 1;
This is not trully architecture independent as it assumes that signed integers are represented using 2's complement logic and that there is no padding bit in the integer representation. But in many cases, this should work fine (tested on x86 pc).

Resources