Why does NOT give an unexpected result when flipping 1? [duplicate] - c++

This question already has answers here:
Explanation of Bitwise NOT Operator
(7 answers)
Closed last year.
I am currently learning the process of bitwise operators, and I've come across something that I can't quite figure out.
Im currently working with the NOT(~) operator, which should invert all of the bits. So in order to get a better understanding of it, I've tried creating a program that will flip the number 1's bits.
int main()
{
int x = 1; // 0001 in binary
int y = ~x; // should flip the bits, so its 1110, or 14
cout << y;
}
However, when running this, i am getting -2 as the result. Can anyone offer an explanation as to why this isn't working?

You're using signed integers. Your expected result (14) would occur if you were using unsigned integers (and if the integer were only 4 bits, which it is not).
Instead, with signed integers, all values with the highest bit set are negative values - that's how Two's Complement works. For example, if you have 16 bits, then values 0b0000_0000_0000_0000 through 0b0111_1111_1111_1111 are assigned to the positive values ("0" through "32767") meanwhile values 0b1000_0000_0000_0000 through 0b1111_1111_1111_1111 are assigned to the negative values ("-32768" through "-1").
Also, int usually is more than 4 bits; it's often 32-bits. The negation of 1 would be 0b1111_1111_1111_1111_1111_1111_1111_1110, not 0b1110.
0b1111_1111_1111_1111_1111_1111_1111_1110 when treated as a signed integer is -2 using the Two's Complement rules.
0b1111_1111_1111_1111_1111_1111_1111_1110 when treated as an unsigned integer is 4,294,967,294, equal to 2^32 - 2.
#include <stdio.h>
#include <cstdint>
// Program prints the following:
// unsigned int_8: 254
// signed int_8: -2
// unsigned int_16 65534
// signed int_16 -2
// unsigned int_32 4294967294
// signed int_32 -2
int main() {
printf( "unsigned int_8: %hhu\n", (uint8_t)~1 );
printf( "signed int_8: %d\n", (int8_t)~1 );
printf( "unsigned int_16 %hu\n", (uint16_t)~1 );
printf( "signed int_16 %d\n", (int16_t)~1 );
printf( "unsigned int_32 %u\n", (uint32_t)~1 );
printf( "signed int_32 %d\n", (int32_t)~1 );
}

Related

printf tilde operator in c

I know that the ~ operator is NOT, so it inverts the bits in a binary number
unsigned int a = ~0, b = ~7;
printf("%d\n",a);
printf("%d\n",b);
printf("%u\n",a);
printf("%u\n",b);
I guessed 0 will be 1 and 7 (0111) will be 8 (1000) but the output was
-1
-8
4294967295
4294967288
how did ~0 and ~7 become -1, and -8? also why is %u printing that long number?
The ~ operator simply inverts all bits in a number.
On most modern compilers, int is 32 bits in size, and a signed int uses 2's complement representation. Which means, among other things, that the high bit is reserved for the sign, and if that bit is 1 then the number is negative.
0 and 7 are int literals. Assuming the above, we get these results:
0 is bits 00000000000000000000000000000000b
= 0 when interpreted as either signed int or unsigned int
~0 is bits 11111111111111111111111111111111b
= -1 when interpreted as signed int
= 4294967285 when interpreted as unsigned int
7 is bits 00000000000000000000000000000111b
= 7 when interpreted as either signed int or unsigned int
~7 is bits 11111111111111111111111111111000b
= -8 when interpreted as signed int
= 4294967288 when interpreted as unsigned int
In your printf() statements, %d interprets its input as a signed int, and %u interprets as an unsigned int. This is why you are seeing the results you get.
The ~ operator inverts all bits of the integer operand. So for example where int is 32-bit, 1 is 0x00000001 in hex and it's one's complement is 0xFFFFFFFE. When interpreted as unsigned, that is 4 294 967 294, and as two's complement signed, -2.

Why does comparing unsigned long with negative number result in false? [duplicate]

This question already has answers here:
Comparison operation on unsigned and signed integers
(7 answers)
Why is (sizeof(int) > -1) false? [duplicate]
(3 answers)
Closed 6 years ago.
unsigned long mynum = 7;
if(mynum > -1) // false
Why does this happen ? is it because -1 is an int, and when it gets "promoted" to unsigned long, it gets the maximum value of unsigned long ?
This might not be right but here's what i think:
When you execute the following code
unsigned long a = -8;
std::cout << a;
Since unsigned values can't be below 0, it will return the max value of an unsigned long - 8 or 4294967288 in this case.
And thats what happened to the -1 in your operation when it got converted to an unsigned long
unsigned variables has the maximum value they don't have a minus sign so the last bit is positive.
assigning a negative value to a unsigned will set the value to the corresponding signed value:
-1 and 255 has the same bitfield set:
#include <iostream>
int main()
{
unsigned char uc1 = 255; // 11111111
unsigned char uc2 = -1;
//signed : -1 : 11111111 : 1 1111111 : -128 + 127
//unsigned: 255: 11111111 : 1 1111111 : 128 + 127
if(uc1 == uc2)
std::cout << "uc1 = uc2" << std::endl;
return 0;
}
This is because of implicit typecast which is performed internally by compiler.
When the operation is going between two different types of variables the compiler itself typecasts (converts temporarily) the lower data type to higher datatype temporarily.
Here in your code -1 temporarily acts as unsigned long because implicit typecasting performed by compiler itself. It behaves as unsigned long because the other variable is pf that type.
here -1 is not treated as -1 but its treated as its equivalent as unsigned long.

Wrap around range of unsigned int in C++?

I am going through C++ Primer 5th Edition and am currently doing the signed/unsigned section. A quick question I have is when there is a wrap-around, say, in this block of code:
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // prints -84
std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264
I thought that the max range was 4294967295 with the 0 being counted, so I was wondering why the wrap-around seems to be done from 4294967296 in this problem.
Unsigned arithmetic is modulo (maximum value of the type plus 1).
If maximum value of an unsigned is 4294967295 (2^32 - 1), the result will be mathematically equal to (10-42) modulo 4294967296 which equals 10-42+4294967296 i.e. 4294967264
When an out-of-range value is converted to an unsigned type, the result is the remainder of it modulo the number of values the target unsigned type can hold. For instance, the result of n converted to unsigned char is n % 256, because unsigned char can hold values 0 to 255.
It's similar in your example, the wrap-around is done using 4294967296, the number of values that a 32-bit unsigned integer can hold.
Given unsigned int that is 32 bits you're correct that the range is [0, 4294967295].
Therefore -1 is 4294967295. Which is logically equivalent to 4294967296 - 1 which should explain the behavior you're seeing.

bit shift for unsigned int, why negative?

Code:
unsigned int i = 1<<31;
printf("%d\n", i);
Why the out put is -2147483648, a negative value?
Updated question:
#include <stdio.h>
int main(int argc, char * argv[]) {
int i = 1<<31;
unsigned int j = 1<<31;
printf("%u, %u\n", i, j);
printf("%d, %d\n", i, j);
return 0;
}
The above print:
2147483648, 2147483648
-2147483648, -2147483648
So, does this means, signed int & unsigned int have the same bit values, the difference is how you treat the 31st bit when convert it to a number value?
%d prints the int version of the unsigned int i. Try %u for unsigned int.
printf("%u\n", i);
int main(){
printf("%d, %u",-1,-1);
return 0;
}
Output: -1, 4294967295
i.e The way a signed integer is stored and how it gets converted to signed from unsigned or vice-versa will help you. Follow this.
To answer your updated question, its how the system represents them i.e in a 2's complement (as in the above case where
-1 =2's complement of 1 = 4294967295.
Use '%u' for unsigned int
printf("%u\n", i);
.......................................................
Response to updated question: any sequence of bits can be interpreted as a signed or unsigned value.
printf("%d\n", i); invokes UB. i is unsigned int and you try to print it as signed int. Writing 1 << 31 instead of 1U << 31 is undefined too.
Print it as:
printf("%u\n", i);
or
printf("%X\n", i);
About your updated question, it also invokes UB for the very same reasons (If you use '1U' instead of 1, then for the reason that an int is initialized with 1U << 31 which is out of range value. If an unsigned is initialized with out of range value, modular arithmetic come into picture and remainder is assigned. For signed the behavior is undefined.)
Understanding the behavior on your platformOn your platform, int appears to be 4 byte. When you write something like 1 << 31, it converts to bit patters 0x80000000 on your machine.
Now when you try to print this pattern as signed, it prints signed interpretation which is -231 (AKA INT_MIN) in 2s completement system. When you print this as unsigned, you get expected 231 as output.
Learnings
1. Use 1U << 31 instead of 1 << 31
2. Always use correct print specifiers in printf.
3. Pass correct argument types to variadic functions.
4. Be careful when implicit typecast (unsigned -> signed, wider type -> narrow type) takes place. If possible, avoid such castings completely.
Try
printf("%u\n", i);
By using %d specifier, printf expects argument as int and it typecast to int.
So, use %u for unsigned int.
You are not doing the shift operation on an unsigned but on a signed int.
1 is signed.
the shift operation then shifts into the sign bit of
that signed (assuming that int is 32 bit wide), that is already undefined behavior
then you assign whatever the compiler thinks he wants for that value to an unsigned.
then you print an unsigned as a signed, again no defined behavior.
%u is for unsigned int.
%d is for signed int.
in your programs output :
2147483648, 2147483648 (output for unsigned int)
-2147483648, -2147483648 (output for signed int )

n bit 2s binary to decimal in C++

I am trying to convert a string of signed binary numbers to decimal value in C++ using stoi as shown below.
stoi( binaryString, nullptr, 2 );
My inputs are binary string in 2s format and stoi will work fine as long as the number of digits is eight. for instance "1100" results 12 because stoi probably perceive it as "00001100".
But for a 4 bit system, 1100 in 2s format equals to -4. Any clues how to do this kind of conversion for arbitrary bit length 2s numbers in C++?
Handle sigendness for numbers with less bits:
convert binary -> decimal
calc 2s-complement if signed bit is set (wherever your sign bit is depending on wordlength).
.
#define BITSIZE 4
#define SIGNFLAG (1<<(BITSIZE-1)) // 0b1000
#define DATABITS (SIGNFLAG-1) // 0b0111
int x= std::stoi( "1100", NULL, 2); // x= 12
if ((x & SIGNFLAG)!=0) { // signflag set
x= (~x & DATABITS) + 1; // 2s complement without signflag
x= -x; // negative number
}
printf("%d\n", x); // -4
You can use strtoul, which is the unsigned equivalent. The only difference is that it returns an unsigned long, instead of an int.
You probably can implement
in C++, where a is binaryString, N is binaryString.size() and w is result.
The correct answer would probably depend on what you ultimately want to do with the int after you convert it. If you want to do signed math with it then you would need to 'sign extend' your result after the stoi conversion -- this is what the compiler does internally on a cast operation from one size signed int to another.
You can manually do this with something like this for a 4-bit system:
int myInt;
myInt = std::stoi( "1100", NULL, 2);
myInt |= myInt & 0x08 ? (-16 ) : 0;
Note, I used 0x08 as the test mask and -16 as the or mask as this is for a 4-bit result. You can change the mask to be correct for whatever your input bit length is. Also using a negative int like this will correctly sign-extend no matter what your systems integer size is.
Example for arbitrary bit width system (I used bitWidth to denote the size:
myInt = std::stoi( "1100", NULL, 2);
int bitWidth = 4;
myInt |= myInt & (1 << (bitWidth-1)) ? ( -(1<<bitWidth) ) : 0;
you can use the bitset header file for this :
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
bitset<4> bs;
int no;
cin>>bs;
if(bs[3])
{
bs[3]=0;
no=-1*bs.to_ulong();
}
else
no=bs.to_ulong();
cout<<no;
return 0;
}
Since it returns unsigned long so you have to check the last bit.