Minus operator used as unary bitwise operation - c

I don't fully understand how the "-" operator affects the following code:
#define COMP(x) ((x) & -(x))
unsigned short a = 0xA55A;
unsigned short b = 0x0400;
Could someone explain what COMP(a) and COMP(b) are and how they are calculated?

(x) & -(x) is equal to the lowest bit set in x when using 2's complement for representing binary numbers.
This means COMP(a) == 0x0002; and COMP(b) == 0x0400;

the "-" sign negative the value of the short parameter in a two's complement way. (in short, turn all 0 to 1, 1 to 0 and then add 1)
so 0xA55A in binary is 1010 0101 0101 1010
then -(0xA55A) in binary is 0101 1010 1010 0110
run & between them will give you 0000 0000 0000 0010

-(x) negates x. Negation in two's complement is the same as ~x+1 (bitflip+1)
as the code below shows:
#include <stdio.h>
#include <stdio.h>
#include <stdint.h>
int prbits(uintmax_t X, int N /*how many bits to print (from the low end)*/)
{
int n=0;
uintmax_t shift=(uintmax_t)1<<(N-1);
for(;shift;n++,shift>>=1) putchar( (X&shift)?'1':'0');
return n;
}
int main()
{
prbits(0xA55A,16),puts("");
//1010010101011010
prbits(~0xA55A,16),puts("");
//0101101010100101
prbits(~0xA55A+1,16),puts("");
//0101101010100110
prbits(-0xA55A,16),puts("");
//0101101010100110 (same)
}
When you bitand a value with its bitfliped value, you get 0. When you bitand a value with its bitfliped value + 1 (=its negated value) you get the first nonzero bit from the right.
Why? If the rightmost bit of ~x is 1, adding 1 to it will yield 0 with carry=1. You repeat this while the rightmost bits are 1 and, zeroing those bits. Once you hit zero (which would be 1 in x, since you're adding 1 to ~x), it gets turned into 1 with carry==0, so the addition ends. To the right you have zeros, to the left you have bitflips. You bitand this with the original and you get the first nonzero bit from the right.

Basically, what COMP does is AND the two operands of which one is in its original form and one of which is a negation of it's form.
How CPUs typically handle signed numbers is using 2's Complement, 2's complement splits the range of a numeric data type to 2, of which (2^n-1) -1 is positive and (2^n-1) is negative.
The MSB (right-most bit) represents the sign of the numeric data
e.g.
0111 -> +7
0110 -> +6
0000 -> +0
1111 -> -1
1110 -> -2
1100 -> -6
So what COMP does by doing an AND on positive and negative version of the numeric data is to get the LSB (Left-most bit) of the first 1.
I wrote some sample code that can help you understand here:
http://coliru.stacked-crooked.com/a/935c3452b31ba76c

Related

Diffrent usage of &- operator

Look at the following code:
#include <stdio.h>
int main()
{
int num, sum;
scanf("%d", &num);
sum = num - (num&-num);
printf("%d", sum);
return 0;
}
The line sum = num - (num& - num) returns value of the given number without the last 1 in binary format. For example if the num is equal to 6(110) it will give the value without the last 1. In this case 100 which is equal to 4.
My question is how does &- work and how could do we do the same thing in octal numeral system?
What you have here is two separate operators: the bitwise AND operator & and the unary negation operator -. So the line in question is actually:
sum = num - (num & -num);
Assuming integers are stored in two's complement representation, negating a value means inverting all bits and adding one.
In the case that num is 6, (binary 00000110), -num is -6 which is 11111010. Then performing a bitwise AND between these two values results in 00000010 in binary which is 2 in decimal, so num - (num & -num) is 6 - 2 which is 4.
There is no &- operator. num - (num&-num) is num - (num & -num), where & performs the bitwise AND of num and its negation, -num.
Consider some number in binary, say 0011 0011 1100 11002 (spaces used for easy visualization). The negative of this is −0011 0011 1100 11002. However, we commonly represent negative numbers using two’s complement, in which a power of two is added. For 16-bit formats, we add 216, which is 1 0000 0000 0000 00002. So, to represent −0011 0011 1100 11002, we use 1 0000 0000 0000 00002 + −0011 0011 1100 11002 = 1100 1100 0011 01002.
Observe what happens in this subtraction, column by column from the right:
In the rightmost column, we have 0−0, which yields 0.
The next column also has 0−0, yielding 0.
The next column has 0−1. This yields 1 with a borrow from the column to the left.
The next column has 0−1−1 (where the second −1 is the borrow). This yields 0 with another borrow.
Because the minuend (the number being subtracted from) has all zeros up to that initial 1, this borrow is never satisfied, so it propagates throughout the bits.
Thus the result is:
Starting at the right, 0s remain 0s.
The first 1 stays a 1 but starts a borrow chain.
Because of the borrow, all bits to the left of that flip from 0 to 1 or 1 to 0.
Thus the subtrahend (the number being subtracted) and the result differ in all bits to the left of the first 1. And they both have 0s to the right of the first 1. So the only bit they both have set is that first 1.
Therefore, when two’s complement is in use, the result of num & -num is the lowest 1 bit that is set in num.
Then num - (num & -num) subtracts this bit from num, leaving it as num with its lowest 1 bit changed to 0.

difficulty understanding signed not

I'm having trouble understanding why c equals -61 on the following program:
main() {
unsigned int a = 60; // 60 = 0011 1100
unsigned int b = 13; // 13 = 0000 1101
int c = 0;
c = ~a; //-61 = 1100 0011
printf("Line 4 - Value of c is %d\n", c );
}
I do understand how the NOT operator works on 0011 1100 (the solution being 1100 0011). But I'm not sure why the decimal number is increased by 1. Is this some sort of type conversion from unsigned int (from a) into signed int (from c) ?
Conversion from a positive to a negative number in twos complement (the standard signed format) constitutes a bitwise inversion, and adding one.
Note that for simplicity I am using a single signed byte.
So if 60 = 0011 1100
Then c = 1100 0011 + 1
= 1100 0100
And for a signed byte, the most significant bit is negative,
so
c = -128 + 64 + 4 = -60
You need to add 1 to account for the fact that the most significant bit is -128, while the largest positive number is 0111 1111 = 127. All negative numbers have a 1 for -128 which needs to be offset.
This is easy to see when you look at converting 0 to -0. Invert 00000000 and you get 11111111 and adding one gets you back to 00000000. Do the same with 1 to -1 and you get 11111111 - the largest possible negative number.

Bitwise XOR operation in C

I'm learning bitwise operation and i came across a xor operation,
#include<stdio.h>
#include<conio.h>
int main
{
printf("%d\n",10 ^ 9);
getch();
return 0;
}
the binary form of 10 ---> 1 0 1 0
the binary form of 9 ---> 1 0 0 1
So in XOR the output is 1 when one of the input is 1 and other is 0.
So the output of 10 ^ 9 is 0 0 1 1 => 3
So when trying for the -10 ^ 9, I'm getting the output as -1.
#include<stdio.h>
#include<conio.h>
int main
{
printf("%d\n",-10 ^ 9);
getch();
return 0;
}
Can some one explain me how it is -1?
Thanks in advance for all who helps!
Because the operator precedence of XOR is lower than the unary minus.
That is, -10 ^ 9 is equal to (-10) ^ 9.
-10 ^ 9 is not equal to -(10 ^ 9).
-10 is 11110110(2) and 9 is 00001001(2).
11110110(2) XOR 00001001(2) = 11111111(2)
11111111(2) is -1 in 2's complement representation.
Continuing from the comment.
In a two's complement system, negative values are represented by values that are sign-extended to the width of the type. Where 10 is 1010 in binary, the two-complement representation for -10 for a 4-byte integer is:
11111111111111111111111111110110
(which has an unsigned value of 4294967286)
Now you see what happens when you xor with 9 (binary 1001),
11111111111111111111111111110110
^ 1001
----------------------------------
11111111111111111111111111111111 (-1 for a signed integer)
The result is 1111 which is sign-extended to 32-bits, or 11111111111111111111111111111111 for a signed int, which is -1.
Binary representation of negative numbers uses a concept called two's complement. Basically, every bit is first flipped and then you add 1.
For example, the 8-bit representation positive 10 would be 00001010. To make -10, first you flip the bits: 11110101, and then you add 1: 11110101 + 1 = 11110110.
So the binary representation of -10 is therefore 11110110
If you XOR this value with 9, it would look then look like this: 11110110 XOR 00001001 = 11111111.
11111111 is the two's complement of 1, therefore the final answer is -1.
The minus '-' sign have higher precedence than the xor '^' operator . So first we find the value of -10.
The binary equivalent of 10 is 1010 & representation in terms of 8-bits becomes 0000 1010 .
For signed numbers , we take a 2's complement of 10 .
First find 1's complement of 0000 1010
0000 1010 ----- 1's complement ---- 1111 0101
Now find 2's complement by adding 1 in 1's complement result .
1's complement --------- 1111 0101
Adding 1 --------- 1
2's complement --------- 1111 0110
Now perform -10^9 (XOR operator gives 1 when both bits are different other wise it gives 0)
-10 ------- 1111 0110
9 ------- 0000 1001
--------------------------
-10^9 ------- 1111 1111
-10^9 = 1111 1111 which is equal to the -1 in signed numbers.
Thats why the output becomes -1 .

How to set and clear bits without ~ operator

I am using a C like script for Bluegiga chip and their scripting langauge does not have the ~ operator in the compiler.
Is there any way to work with bits using pure math?
For example i read a byte and i need to clear bit 1 and set bit 2.
The following bitwise operations are supported:
Operation Symbol
AND &
OR |
XOR ^
Shift left <<
Shift right >>
The following mathematical operators are supported:
Operation Symbol
Addition: +
Subtraction: -
Multiplication: *
Division: /
Less than: <
Less than or equal: <=
Greater than: >
Greater than or equal: >=
Equals: =
Not equals: !=
Just use OR and AND operations. To do that operation:
initial byte: 0000 0001
clear bit 1: 0000 0001 & 1111 1110 --> result - 0000 0000 (The 1st bit of the second operand must be 0 to clear the bit)
now set bit 2: 0000 0000 | 0000 0010 --> result - 0000 0010 (The 2st bit of the second operand must be 1 to set the bit)
Note that for this operations you only change the specific bit all the other remain with the same value.
Also to obtain the second operand you can just obtain it by:
for the set operation on the n bit - the second operand is 2^n
for the clear operation on the n bit - the second operand is 1111 1111 XOR 2^n (in this case 1111 1111 XOR is used for the not operation).
If you are missing the ~ operator, you can make your own using XOR and a constant.
#include<stdio.h>
int main()
{
unsigned int s = 0xFFFFFFFF ;
printf("%#x" , 0xFF ^ s ) ; //XOR with the constant is equivalent to ~
unsigned int byte = 0x4 ;
printf("%#x" , 0x5 & ( byte ^ s ) ) ; //clear those bits
return 0 ;
}
When you have ~ it is easy to clear the bits.
Clearing a (single) bit is also equivalent to SET following by INVERT (or xor). Thus.
aabbccdd <-- original value
00000110 OR
00000010 XOR
--------
aabbc10d <-- result (I'm counting the bits from 7 downto 0)
This approach has the benefit of being scalable from byte to the native integer size without the burden of calculating the mask for AND operation.
Performing a XOR against -1 will invert all the bits in an integer.

Why does the following bitwise operation return an unintended result?

3 bits can hold up to a maximum number of 7 (4 + 2 + 1). I'm trying to calculate this using a bitwise operation.
3 is 0b011
~3 is 0b100
Doing a bitwise OR I would expect 0b111 (i.e. 7). Instead I get
int result = (~3) | 3;
printf("%i\n", result);
-1
What am I doing wrong?
You are doing everything right: N | ~N results in a number with binary representation consisting of all ones. Such number is interpreted as -1 in two's compliment representation of negative numbers.
How many bits wide is an int? You seem to think it's three bits wide. Certainly not correct! Guess again. What is ~0u? Try printf("%u\n", ~0u);. What about ~1u? ... and ~2u? Do you notice a pattern?
Note the u suffix, which tells the compiler that it's an unsigned literal. You can't work with signed integer types with the ~ operator... Well, you can, but you might run into trap representations and negative zeros, according to 6.2.6.2 of n1570.pdf. Using a trap representation is undefined behaviour. That might work on your system, but only by coincidence. Do you want to rely upon coincidence?
Similarly, I suggest using the %u directive to print unsigned values, as %d would produce undefined behaviour according to 7.21.6.1p29 of n1570.pdf.
When you do ~3 you are inverting the bits that make up 3 - so you turn 0000 0000 0000 0000 0000 0000 0000 0011 into 1111 1111 1111 1111 1111 1111 1111 1100. Since the high bit is set, this is interpreted as a negative number - all 1s is -1, one less than that is -2, one less -3 and so on. This number is the signed 32 bit integer for -4.
If you binary OR this with 3, you get all 1s (by definition) - which is the signed 32 bit integer for -1.
Your only problem is that you think you are working with 3 bit numbers, but you are actually working with 32 bit numbers.
After doing this in the code
int result = (~3) | 3;
Add this line
result= result & 0x07
This will give you the answer that you expect.
#include <stdio.h>
int main (){
unsigned d3 = 0b011;
unsigned invd3 = ~d3;
unsigned d4 = 0b100;
unsigned result = d3 | invd3;
printf("%X\n", result);//FFFFFFFF
result = d3 | d4;
printf("%X\n", result);//7
return 0;
}

Resources