Can't change -1 using right shift operattions - bit-manipulation

I can't seem to understand why does -1 isn't getting changed under bitwise shift.
why does -1>>1=-1?

A signed bit shift doesn't just shift the bits for negative numbers. The reason for this is you would get the wrong result. -1 in twos complement has all the bits set i.e. it's:
111111...1
If you were to just shift this you'd get:
011111....1
In two's complement this would be the representation of the largest positive number instead of anything that you might expect, it's the same for any negative number simply shifting would make the number positive. A simple way of implementing a right shift in twos complement is this:
rightShiftVal(int val) {
if (int < 0) {
int res = ~val; //not the value.
res = res >> 1; //do the right shift (the direction of the shift is correct).
res = ~res; //Back to twos complement.
return res;
}
return val >> 1;
}
If you put -1 into the above algorithm (i.e. 11111...111) when you not the value you get 0, when you shift the value you get 0, then when you not 0 you back to 11111....111, the representation of -1. For all other values the algorithm should work as expected.
Update
As suggested in one of the other answers you can also shift right and add the bit on at the far left i.e.
if (val < 0) {
unsigned uVal = val;
uVal = (uVal >> 1);
uVal = uVal | 0x80000000; //bitwise or with 1000...0
return uVal
}
Note that for this to work you have to put your int into an unsigned int so it doesn't do the signed bit shift. Again if you work through this with the value 11111...1 (the representation of -1) you are left with 11111....1, so there is no change.

Because >> operator is a signed right shift operator which fills in the bit by moving it by 1 with the sign bit in your case. See this for brief discussion.

The negative nos. are stored in the form of 2's complementin the memory.
So, if you have a no. -5 it will be stored as:
1111 1011
and 2's complement of -1 is: 1111 1111
So, when you right shift it you get 1111 1111 that is again -1.
Note:
1.While storing negative no. MSB is used as sign bit. 0 indicates positive no. and 1 indicates negative no.
2.When you right shift a positive no. a 0 is added to the left and for negative nos. 1 is added to keep the sign.

Related

Is ~i really equivalent to i != -1?

How does ~i work in C++?
I just noticed it is equivalent to i != -1, but I'm not certain about that.
int arr[3] {1, 2, 3};
int n = 3;
for (int i = n - 1; ~i; i--) {
cout << arr[i] << ' ';
}
It printed the array in reverse.
~ is the bitwise NOT operator. ~i is 0 if and only if i has 1 in all its bits. Whether -1 has all bits 1 depends on how signed numbers are represented on the system. In two's complement representation, -1 is represented with all bits 1, so on such systems ~(-1) == 0. Neither in one's complement, nor in sign-and-magnitude does that hold true.
Therefore, the answer is no; not on all systems. That said, two's complement is fairly ubiquitous in modern machines (everything made since the 90's), and on such systems, the answer is yes. Regardless of the sign representation however, i != -1 is much more readable.
~i is bitwise NOT operator. I.e. it inverts every bit in i.
-1 is represented binary as every bit of number being set to 1, inverting every bit to 0 gets you 0. And when checking integer in place where bool is expected 0 is treated as false and any other number as true.
So, in this particular case yes, ~i is equivalent with i != -1.
Because your i variable from for loop is of type int, which is defined as signed integer, and as such in twos complement, its binary representation of value -1 is all bits set, what means all bits are 1. On other side, bitwise negation of all ones is all zeros, and that is what you need, loop to execute until i>=0 or i!=-1, since you decrementing i. In that context of bitwise operations on sign values on system has twos complement binary representation of int, yes, it is the same.

What is the purpose of "int mask = ~0;"?

I saw the following line of code here in C.
int mask = ~0;
I have printed the value of mask in C and C++. It always prints -1.
So I do have some questions:
Why assigning value ~0 to the mask variable?
What is the purpose of ~0?
Can we use -1 instead of ~0?
It's a portable way to set all the binary bits in an integer to 1 bits without having to know how many bits are in the integer on the current architecture.
C and C++ allow 3 different signed integer formats: sign-magnitude, one's complement and two's complement
~0 will produce all-one bits regardless of the sign format the system uses. So it's more portable than -1
You can add the U suffix (i.e. -1U) to generate an all-one bit pattern portably1. However ~0 indicates the intention clearer: invert all the bits in the value 0 whereas -1 will show that a value of minus one is needed, not its binary representation
1 because unsigned operations are always reduced modulo the number that is one greater than the largest value that can be represented by the resulting type
That on a 2's complement platform (that is assumed) gives you -1, but writing -1 directly is forbidden by the rules (only integers 0..255, unary !, ~ and binary &, ^, |, +, << and >> are allowed).
You are studying a coding challenge with a number of restrictions on operators and language constructions to perform given tasks.
The first problem is return the value -1 without the use of the - operator.
On machines that represent negative numbers with two's complement, the value -1 is represented with all bits set to 1, so ~0 evaluates to -1:
/*
* minusOne - return a value of -1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 2
* Rating: 1
*/
int minusOne(void) {
// ~0 = 111...111 = -1
return ~0;
}
Other problems in the file are not always implemented correctly. The second problem, returning a boolean value representing the fact the an int value would fit in a 16 bit signed short has a flaw:
/*
* fitsShort - return 1 if x can be represented as a
* 16-bit, two's complement integer.
* Examples: fitsShort(33000) = 0, fitsShort(-32768) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 1
*/
int fitsShort(int x) {
/*
* after left shift 16 and right shift 16, the left 16 of x is 00000..00 or 111...1111
* so after shift, if x remains the same, then it means that x can be represent as 16-bit
*/
return !(((x << 16) >> 16) ^ x);
}
Left shifting a negative value or a number whose shifted value is beyond the range of int has undefined behavior, right shifting a negative value is implementation defined, so the above solution is incorrect (although it is probably the expected solution).
Loooong ago this was how you saved memory on extremely limited equipment such as the 1K ZX 80 or ZX 81 computer. In BASIC, you would
Let X = NOT PI
rather than
LET X = 0
Since numbers were stored as 4 byte floating points, the latter takes 2 bytes more than the first NOT PI alternative, where each of NOT and PI takes up a single byte.
There are multiple ways of encoding numbers across all computer architectures. When using 2's complement this will always be true:~0 == -1. On the other hand, some computers use 1's complement for encoding negative numbers for which the above example is untrue, because ~0 == -0. Yup, 1s complement has negative zero, and that is why it is not very intuitive.
So to your questions
the ~0 is assigned to mask so all the bits in mask are equal 1 -> making mask & sth == sth
the ~0 is used to make all bits equal to 1 regardless of the platform used
you can use -1 instead of ~0 if you are sure that your computer platform uses 2's complement number encoding
My personal thought - make your code as much platform-independent as you can. The cost is relatively small and the code becomes fail proof

What does ~ exactly do when used in bit wise operations?

What is the difference between ~i and INT_MAX^i
Both give the same no. in binary but when we print the no. the output is different as shown in the code below
#include <bits/stdc++.h>
using namespace std;
void binary(int x)
{
int i=30;
while(i>=0)
{
if(x&(1<<i))
cout<<'1';
else
cout<<'0';
i--;
}
cout<<endl;
}
int main() {
int i=31;
int j=INT_MAX;
int k=j^i;
int g=~i;
binary(j);
binary(i);
binary(k);
binary(g);
cout<<k<<endl<<g;
return 0;
}
I get the output as
1111111111111111111111111111111
0000000000000000000000000011111
1111111111111111111111111100000
1111111111111111111111111100000
2147483616
-32
Why are k and g different?
K and g are different - the most significant bit is different. You do not display it since you show only 31 bits. In k the most significant bit is 0 (as the result of XOR of two 0's). In g it is 1 as the result of negation of 0 (the most significant bit of i).
Your test is flawed. If you output all of the integer's bits, you'll see that the values are not the same.
You'll also now see that NOT and XOR are not the same operation.
Try setting i = 31 in your binary function; it is not printing the whole number. You will then see that k and g are not the same; g has the 'negative' flag (1) on the end.
Integers use the 32nd bit to indicate if the number is positive or negative. You are only printing 31 bits.
~ is bitwise NOT; ~11100 = ~00011
^ is bitwise XOR, or true if only one or the other
~ is bitwise NOT, it will flip all the bits
Example
a: 010101
~a: 101010
^ is XOR, it means that a bit will be 1 iff one bit is 0 and the other is 1, otherwise it will set to 0.
a: 010101
b: 001100
a^b: 011001
You want UINT_MAX. And you want to use unsigned int's INT_MAX only does not have the signed bit set. ~ will flip all the bits, but ^ will leave the sign bit alone because it is not set in INT_MAX.
This statement is false:
~i and INT_MAX^i ... Both give the same no. in binary
The reason it appears that they give the same number in binary
is because you printed out only 31 of the 32 bits of each number.
You did not print the sign bit.
The sign bit of INT_MAX is 0 (indicating a positive signed integer)
and is is not changed during INT_MAX^i
because the sign bit of i also is 0,
and the XOR of two zeros is 0.
The sign bit of ~i is 1 because the sign bit of i was 0 and the
~ operation flipped it.
If you printed all 32 bits you would see this difference in the binary output.

why shift int a=1 to left 31 bits then to right 31 bits, it becomes -1

given
int a = 1; (00000000000000000000000000000001),
what I did is just
a=(a<<31)>>31;
I assume a should still be 1 after this statement (nothing changed I think). However, it turns out to be -1 (11111111111111111111111111111111). Anyone knows why?
What you are missing is that in C++ right shift >> is implementation defined. It could either be logical or arithmetic shift for a signed value. In this case it's shifting in 1s from the left to retain the sign of the shifted value. Typically you want to avoid doing shifts on signed values unless you know precisely that they will be positive or that the shift implementation doesn't matter.
Look at it in steps:
#include <cstdio>
using namespace std;
int main()
{
int a = 1;
printf("%d = %x\n", a, a);
a <<= 31;
printf("%d = %x\n", a, a);
a >>= 31;
printf("%d = %x\n", a, a);
return 0;
}
Output:
1 = 1
-2147483648 = 80000000
-1 = ffffffff
1 got shifted all the way up to the high bit which makes it a negative number. Shifting back down triggers sign extension to maintain the negative.
Change the declaration of a to unsigned int a and you will get the behaviour you expect.
" however it turns out to be -1"
You use an unsigned int to do so for seeing only 32 bit values that are greater than 0:
unsigned int a = 1;
a=(a<<31)>>31;
It is a signed shift so the left most bit will be extended. That way the overall number is on the same side of 0.
By left shifting that much you put the lowest bit into the sign bit and end up with a negative number.
When you then do a right shift it sign extends, copying the sign bit down to the lower 31 bits.
If you want to know the lowest bit just do & 1.

Why does a right shift on a signed integer causes an overflow?

Given any 8 bits negative integer (signed so between -1 and -128), a right shift in HLA causes an overflow and I don't understand why. If shifted once, it should basically divide the value by 2. This is true for positive numbers but obviously not for negative. Why? So for example if -10 is entered the result is +123.
Program cpy;
#include ("stdlib.hhf")
#include ("hla.hhf")
static
i:int8;
begin cpy;
stdout.put("Enter value to divide by 2: ");
stdin.geti8();
mov(al,i);
shr(1,i); //shift bits one position right
if(#o)then // if overlow
stdout.put("overflow");
endif;
end cpy;
Signed numbers are represented with their 2's complement in binary, plus a sign bit "on the left".
The 2's complement of 10 coded on 7 bits is 1110110, and the sign bit value for negative numbers is 1.
-10: 1111 0110
^
|
sign bit
Then you shift it to the right (when you right shift zeroes get added to the left):
-10 >> 1: 0111 1001
^
|
sign bit
Your sign bit is worth 0 (positive), and 1111011 is 123 in decimal.