Is there an easy way to replace an overflow at counting down with a negative value?
For example a 32 bit variable. Possible values are 0x00000000 - 0xFFFFFFFF. When I subtract 1 from the lowest possible value (0x00000000 - 1), the result is 0xFFFFFFFF. How can the operation be changed to give a result of -1?
Is there an easy way to replace an overflow at counting down with a negative value?
Use wider math is a direct approach.
"example a 32 bit variable. Possible values are 0x00000000 - 0xFFFFFFFF" implies that the variable is some unsigned type like uint32_t.
Subtracting 1 from (uint32_t)0 is (uint32_t)0xFFFFFFFF as OP reported. So instead use a wider signed math like long long (which is at least 64-bit) or int64_t
// Insure subtraction is done using `long long` math with 1LL
long long result = var_uint32_bit - 1LL;
Alternatively code could stick with a corresponding same width signed type.
// Only non-implementation defined for values 0...0x7FFFFFFF
int32_t result = (int32_t)var_uint32_bit - 1;
The (int32_t)var_uint32_bit has a limitation concerning conversion of an unsigned type to a signed integer type.
Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised. C11dr §6.3.1.3 3
Related
I want the following idea: I have short a = -4; and I have an unsigned short b = (unsigned short)a;
When I printf("%hu", b), why doesn't it print 4? How can I convert a negative integer to a positive integer using casting?
short and unsigned short are normally 16 bit integers. So limits are -32768 to 32767 for the signed version (short) and 0 to 65535 for unsigned short. Casting from signed to unsigned just wraps values, so -4 will be casted to 65532.
This is the way casting to unsigned works in C language.
If you accept to use additions/substractions, you can do:
65536l - (unsigned short) a
The operation will use the long type (because of the l suffix) which is required to be at least a 32 bits integer type. That should successfully convert any negative short integer to its absolute value.
It sounds like you want the absolute value of the number, not a cast. In C we have the abs / labs / llabs functions for that, found in <stdlib.h>.
If you know ahead of time that the value is negative, you can also just negate it: -a.
If you were instead just looking to get the absolute value, you should have used the abs() function from <stdlib.h>.
Otherwise, when you make such a cast, you trigger the following conversion rule from C17 6.3.1.3:
Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. 60)
Where foot note 60) is important:
The rules describe arithmetic on the mathematical value, not the value of a given type of expression.
Mathematical value meaning we shouldn't consider wrap-around etc when doing the calculation. And the signedness format (2's complement etc) doesn't matter either. Applying this rule, then:
You have mathematical value -4 and convert from signed short to unsigned short.
We add one more than the maximum value. That is -4 + USHRT_MAX + 1, where UINT_MAX is likely 2^16 = 65535.
-4 + 65535 + 1 = 65532. This is in range of the new type unsigned short.
We got in range at the first try, but "repeatedly adding or subtracting" is essentially the same as taking the value modulo (max + 1).
This conversion is well-defined and portable - you will get the same result on all systems where short is 16 bits.
What language in the standard makes this code work, printing '-1'?
unsigned int u = UINT_MAX;
signed int s = u;
printf("%d", s);
https://en.cppreference.com/w/c/language/conversion
otherwise, if the target type is signed, the behavior is implementation-defined (which may include raising a signal)
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
GCC supports only two’s complement integer types, and all bit patterns are ordinary values.
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3):
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
To me it seems like converting UINT_MAX to an int would therefore mean dividing UINT_MAX by 2^(CHAR_BIT * sizeof(int)). For the sake of argument, with 32 bit ints, 0xFFFFFFFF / 2^32 = 0xFFFFFFFF. So this doesnt really explain how the value '-1' ends up in the int.
Is there some language somewhere else that says after the modulo division we just reinterpret the bits? Or some other part of the standard that takes precedence before the parts I have referenced?
No part of the C standard guarantees that your code shall print -1 in general. As it says, the result of the conversion is implementation-defined. However, the GCC documentation does promise that if you compile with their implementation, then your code will print -1. It's nothing to do with bit patterns, just math.
The clearly intended reading of "reduced modulo 2^N" in the GCC manual is that the result should be the unique number in the range of signed int that is congruent mod 2^N to the input. This is a precise mathematical way of defining the "wrapping" behavior that you expect, which happens to coincide with what you would get by reinterpreting the bits.
Assuming 32 bits, UINT_MAX has the value 4294967295. This is congruent mod 4294967296 to -1. That is, the difference between 4294967295 and -1 is a multiple of 4294967296, namely 4294967296 itself. Moreover, this is necessarily the unique such number in [-2147483648, 2147483647]. (Any other number congruent to -1 would be at least -1 + 4294967296 = 4294967295, or at most -1 - 4294967296 = -4294967297). So -1 is the result of the conversion.
In other words, add or subtract 4294967296 repeatedly until you get a number that's in the range of signed int. There's guaranteed to be exactly one such number, and in this case it's -1.
uint32_t a = -1; // 11111111111111111111111111111111
int64_t b = (int64_t) a; // 0000000000000000000000000000000011111111111111111111111111111111
int32_t c = -1; // 11111111111111111111111111111111
int64_t d = (int64_t) c; // 1111111111111111111111111111111111111111111111111111111111111111
From the observation above, it appears that only the original value's sign matters.
I.e if the original 32 bit number is unsigned, casting it to a 64 bit value will add 0's to its left regardless of the destination value being signed or unsigned and;
if the original 32 bit number is signed and negative, casting it to a 64 bit value will add 1's to its left regardless of the destination value being signed or unsigned.
Is the above statement correct?
Correct, it's the source operand that dictates this.
uint32_t a = -1;
int64_t b = (int64_t) a;
No sign extension happens here because the source value is an unsigned uint32_t. The basic idea of sign extension is to ensure the wider variable has the same value (including sign). Coming from an unsigned integer type, the value is positive, always. This is covered by the standards snippet /1 below.
Negative sign extension (in the sense that the top 1-bit in a two's complement value is copied to all the higher bits in the wider type(a)) only happens when a signed type is extended in width, since only signed types can be negative.
If the original 32 bit number is signed and negative, casting it to a 64 bit value will add 1's to its left regardless of the destination value being signed or unsigned.
This is covered by the standards snippet /2 below. You still have to maintain the sign of the value when extending the bits but pushing a negative value (assuming the source was negative) into an unsigned variable will simply mathematically add the MAX_VAL + 1 to the value until it is within the range of the target type (in reality, for two's complement, no adding is done, it just interprets the same bit pattern in a different way).
Both these scenarios are covered in the standard, in this case C11 6.3.1.3 Signed and unsigned integers /1 and /2:
1/ When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
2/ Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
3/ Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
Note that your widening conversions are covered by the first two points above. I've included the third point for completion as it covers things like conversion from uint32_t to int32_t, or unsigned int to long where they have the same width (they both have a minimum range but there's no requirement that unsigned int be "thinner" than long).
(a) This may be different in ones' complement or sign-magnitude representations but, since they're in the process of being removed, nobody really cares that much.
See:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r1.html (WG21, C++); and
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2218.htm (WG14, C)
for more detail.
In any case, the fixed width types are two's complement so you don't have to worry about this aspect for your example code.
I was reading John Regehr's blog on how he gives his students an assignment about saturating arithmetic. The interesting part is that the code has to compile as-is while using typedefs to specify different integer types, see the following excerpt of the full header:
typedef signed int mysint;
//typedef signed long int mysint;
mysint sat_signed_add (mysint, mysint);
mysint sat_signed_sub (mysint, mysint);
The corresponding unsigned version is simple to implement (although I'm actually not sure if padding bits wouldn't make that problematic too), but I actually don't see how I can get the maximum (or minimum) value of an unknown signed type in C, without using macros for MAX_ und MIN_ or causing undefined behavior.
Am I missing something here or is the assignment just flawed (or more likely I'm missing some crucial information he gave his students)?
I don't see any way to do this without making assumptions or invoking implementation-defined (not necessarily undefined) behavior. If you assume that there are no padding bits in the representation of mysint or of uintmax_t, however, then you can compute the maximum value like this:
mysint mysint_max = (mysint)
((~(uintmax_t)0) >> (1 + CHAR_BITS * (sizeof(uintmax_t) - sizeof(mysint))));
The minimum value is then either -mysint_max (sign/magnitude or ones' complement) or -mysint_max - 1 (two's complement), but it is a bit tricky to determine which. You don't know a priori which bit is the sign bit, and there are possible trap representations that differ for different representations styles. You also must be careful about evaluating expressions, because of the possibility of "the usual arithmetic conversions" converting values to a type whose representation has different properties than those of the one you are trying to probe.
Nevertheless, you can distinguish the type of negative-value representation by computing the bitwise negation of the mysint representation of -1. For two's complement the mysint value of the result is 0, for ones' complement it is 1, and for sign/magnitude it is mysint_max - 1.
If you add the assumption that all signed integer types have the same kind of negative-value representation then you can simply perform such a test using an ordinary expression on default int literals. You don't need to make that assumption, however. Instead, you can perform the operation directly on the type representation's bit pattern, via a union:
union mysint_bits {
mysint i;
unsigned char bits[sizeof(mysint)];
} msib;
int counter = 0;
for (msib.i = -1; counter < sizeof(mysint); counter += 1) {
msib.bits[counter] = ~msib.bits[counter];
}
As long as the initial assumption holds (that there are no padding bits in the representation of type mysint) msib.i must then be a valid representation of the desired result.
I don't see a way to determine the largest and smallest representable values for an unknown signed integer type in C, without knowing something more. (In C++, you have std::numeric_limits available, so it is trivial.)
The largest representable value for an unsigned integer type is (myuint)(-1). That is guaranteed to work independent of padding bits, because (§ 6.3.1.3/1-2):
When a value with integer type is converted to another integer type… if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
So to convert -1 to an unsigned type, you add one more than the maximum representable value to it, and that result must be the maximum representable value. (The standard makes it clear that the meaning of "repeatedly adding or subtracting" is mathematical.)
Now, if you knew that the number of padding bits in the signed type was the same as the number of padding bits in the unsigned type [but see below], you could compute the largest representable signed value from the largest representable unsigned value:
(mysint)( (myuint)(-1) / (myuint)2 )
Unfortunately, that's not enough to compute the minimum representable signed value, because the standard permits the minimum to be either one less than the negative of the maximum (2's-complement representation) or exactly the negative of the maximum (1's-complement or sign/magnitude representations).
Moreover, the standard does not actually guarantee that the number of padding bits in the signed type is the same as the number of padding bits in the unsigned type. All it guarantees is that the number of value bits in the signed type be no greater than the number of value bits in the unsigned type. In particular, it would be legal for the unsigned type to have one more padding bit than the corresponding signed type, in which case they would have the same number of value bits and the maximum representable values would be the same. [Note: a value bit is neither a padding bit nor the sign bit.]
In short, if you knew (for example by being told) that the architecture were 2's-complement and that corresponding signed and unsigned types had the same number of padding bits, then you could certainly compute both signed min and max:
myuint max_myuint = (myuint)(-1);
mysint max_mysint = (mysint)(max_myuint / (my_uint)2);
mysint min_mysint = (-max_mysint) - (mysint)1;
Finally, casting an out-of-range unsigned integer to a signed integer is not undefined behaviour, although most other signed overflows are. The conversion, as indicated by §6.3.1.3/3, is implementation-defined behaviour:
Otherwise, the new type is signed and the value cannot be represented in it; either the
result is implementation-defined or an implementation-defined signal is raised.
Implementation-defined behaviour is required to be documented by the implementation. So, suppose we knew that the implementation was gcc. Then we could examine the gcc documentation, where we would read the following, in the section "C Implementation-defined behaviour":
Whether signed integer types are represented using sign and
magnitude, two's complement, or one's complement, and whether the
extraordinary value is a trap representation or an ordinary value
(C99 6.2.6.2).
GCC supports only two's complement integer types, and all bit
patterns are ordinary values.
The result of, or the signal raised by, converting an integer to a
signed integer type when the value cannot be represented in an
object of that type (C90 6.2.1.2, C99 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo
2^N to be within range of the type; no signal is raised.
Knowing that signed integers are 2s-complement and that unsigned to signed conversions will not trap, but will produce the expected pattern of low-order bits, we can find the maximum and minimum values for any signed type starting with the maximum representable value for the widest unsigned type, uintmax_t:
uintmax_t umax = (uintmax_t)(-1);
while ( (mysint)(umax) < 0 ) umax >>= 1;
mysint max_mysint = (mysint)(umax);
mysint min_mysint = (-max_mysint) - (mysint)1;
This is a suggestion for getting the MAX value of a specific type set with typedef without using any library
typedef signed int mysint;
mysint size; // will give the size of the type
size=sizeof(mysint)*(mysint)8-(mysint)1; // as it is signed so a bit
// will be deleted for sign bit
mysint max=1;//start with first bit
while(--size)
{
mysint temp;
temp=(max<<(mysint)1)|(mysint)1;// set all bit to 1
max=temp;
}
/// max will contain the max value of the type mysint
If you assume eight-bit chars and a two's complement representation (both reasonable on all modern hardware, with the exception of some embedded DSP stuff), then you just need to form an unsigned integer (use uintmax_t to make sure it's big enough) with sizeof(mysint)*8 - 1 1's in the bottom bits, then cast it to mysint. For the minimum value, negate the maximum value and subtract one.
If you don't want to assume those things, then it's still possible, but you'll need to do some more digging through limits.h to compensate for the size of chars and the sign representation.
I guess this should work irrespective of negative number representation
// MSB is 1 and rests are zero is minimum number in both 2's and 1's
// compliments representations.
mysint min = (1 << (sizeof(mysint) * 8 - 1));
mysint max = ~x;
This C code tries to find the absolute value of a negative number but the output also is negative. Can anyone tell me how to overcome this?
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
int main() {
int64_t a = 0x8000000000000000;
a = llabs(a);
printf("%" PRId64 "\n", a);
return 0;
}
Output
-9223372036854775808
UPDATE:
Thanks for all your answers. I understand that this is a non-standard value and that is why I am unable to perform an absolute operation on it. However, I did encounter this in an actual codebase that is a Genetic Programming simulation. The "organisms" in this do not know about the C standard and insist on generating this value :) Can anyone tell me an efficient way of working around this? Thanks again.
If the result of llabs() cannot be represented in the type long long, then the behaviour is undefined. We can infer that this is what's happening here - the out-of-range value 0x8000000000000000 is being converted to the value -9223372036854775808 when converted to int64_t, and your long long value is 64 bits wide, so the value 9223372036854775808 is unrepresentable.
In order for your program to have defined behaviour, you must ensure that the value passed to llabs() is not less than -LLONG_MAX. How you do this is up to you - either modify the "organisms" so that they cannot generate this value (eg. filter out those that create the out-of-range value as immediately unfit) or clamp the value before you pass it to llabs().
Basically, you can't.
The range of representable values for int64_t is -263 to +263-1. (And the standard requires int64_t to have a pure 2's-complement representation; if that's not supported, an implementation just won't define int64_t.)
That extra negative value has no corresponding representable positive value.
So unless your system has an integer type bigger than 64 bits, you're just not going to be able to represent the absolute value of 0x8000000000000000 as an integer.
In fact, your program's behavior is undefined according to the ISO C standard. Quoting section 7.22.6.1 of the N1570 draft of the 2011 ISO C standard:
The abs, labs, and llabs functions compute the absolute
value of an integer j. If the result cannot be represented, the
behavior is undefined.
For that matter, the result of
int64_t a = 0x8000000000000000;
is implementation-defined. Assuming long long is 64 bits, that constant is of type unsigned long long. It's implicitly converted to int64_t. It's very likely, but not guaranteed, that the stored value will be -263, or -9223372036854775808. (It's even permitted for the conversion to raise an implementation-defined signal, but that's not likely.)
(It's also theoretically possible for your program's behavior to be merely implementation-defined rather than undefined. If long long is wider than 64 bits, then the evaluation of llabs(a) is not undefined, but the conversion of the result back to int64_t is implementation-defined. In practice, I've never seen a C compiler with long long wider than 64 bits.)
If you really need to represent integer values that large, you might consider a multi-precision arithmetic package such as GNU GMP.
0x8000000000000000 is the smallest number that can be represented by a signed 64-bit integer. Because of quirks in two's complement, this is the only 64-bit integer with an absolute value that cannot be represented as a 64-bit signed integer.
This is because 0x8000000000000000 = -2^63, while the maximum representable 64-bit integer is 0x7FFFFFFFFFFFFFFF = 2^63-1.
Because of this, taking the absolute value of this is undefined behaviour that will generally result in the same value.
A signed 64-bit integer ranges from −(2^63) to 2^63 − 1, The absolute value of 0x8000000000000000, or −(2^63), is 2^63, is bigger than the max 64-bit integer.
No signed integer with its highest bit set high and all other bits low is representable in the same type as absolute value of that integer.
Observe an 8-bit integer
int8_t x = 0x80; // binary 1000_0000, decimal -128
An 8-bit signed integer can hold values between -128 and +127 inclusive, so the value +128 is out of range.
For a 16-bit integer this hols as well
int16_t = 0x8000; // binary 1000_0000_0000_0000, decimal -32,768
A 16-bit integer can hold values between -32,768 and +32,767 inclusive.
This pattern holds for any size integer as long as it is represented in two's complement, as is the de-facto representation for integers in computers. Two's complement holds 0 as all bits low and -1 as all bits high.
So an N-bit signed integer can hold values between 2^(N-1) and 2^(N-1)-1 inclusive, an unsigned integer can hold values between 0 and 2^N-1 inclusive.
Interestingly:
int64_t value = std::numeric_limits<int64_t>::max();
std::out << abs(value) << std::endl;
yields a value of 1 on gcc-9.
Frustrating!