Assignment operators are not something I expected to struggle with. Everything in this section so far is familiar, but the way they explain it makes it seem foreign. I think it's the bitwise operators I'm confused about.
Anyway here is the part I don't get.
The function bitcount counts the number of 1-bits in its integer argument.
/*bitcount: count 1 bits in x */
int bitcount (unsigned x)
{
int b;
for(b=0; x != 0; x >>= 1) {
if(x & 01)
b++;
return b;
}
Declaring the argument x to be unsigned ensures that when it is right-shifted, vacated bits will be filled with zeros, not sign bits, regardless of the machine the program is run on.
Not that I really understand the code, but this last sentence is confusing me the most. What does this mean? Does it mean "ones" by "sign bits" and does this have to do with twos complement?
I really had trouble getting through the bitwise operations. Can anyone recommend some comprehensive material to supplement the bitwise stuff in this book?
Suppose x is two’s complement. For illustration, let‘s use an eight-bit width. (C always shifts in a wider width, at least that of int.)
If x is 64 (010000002) and we shift it right one bit, we get 32 (001000002). When we repeat that, we get 16 (000100002), 8 (000010002), 4 (000001002), 2 (000000102) , and 1 (000000012).
When x is −64, two’s complement represents it with 110000002. If we shift that right and bring in a 0 bit, the bits are 011000002, which represents 64+32 = 96. So −64 becomes 96. Now, that might be fine if one were just working with bits. But, if we want to use bit-shifting to divide numbers, we want −32, not 96. The bits for −32 are 111000002. So we can get that by bring in a 1 bit instead of a 0 bit. And the bits for −16 are 111100002. Then −8, −4, −2, and −1 are 111110002, 111111002, 111111102, 111111112. In each case, we bring in a 1 bit when shifting.
So, if we want to use bit-shifting for division, there is a simple rule for a one-bit shift: Shift all bits right one spot and leave the sign bit as is (0 or 1). If we are shifting more than one bit, keep copying the sign bit.
That is called an arithmetic right shift. So, we have two kinds of right shift: An arithmetic right shift that copies the sign bit, and a logical right shift that brings in 0 bits.
For unsigned types, the C standard says a right shift is logical.
For signed types, the C standard does not say whether it is arithmetic or logical. It leaves it to the implementation to define which that implementation uses (or possibly to define something else). That might be due to the history; early machines might not have provided arithmetic right-shift instructions (and may not even have used two’s complement), although it seems hard to imagine these days.
So, when you are writing code that shifts right and you want to be sure of the result you will get, you can use an unsigned type to be sure to get a logical shift.
In twos complement representation the highest order bit is reserved for the sign. The highest order bit is 0 for positive numbers and 1 for negative numbers.
If you right shift the bits of a negative number the 1 originally in the highest order bit will be shifted to the next lower order bit, eventually ending up in the lowest order bit if you keep shifting the bits.
In the code the for loop shifts the bits of x by one bit position and assigns the shifted value to x.
for (b = 0; x != 0; x >>=1 )
First b, which is used to count the number of 1 bits in the number is set to 0.
The condition to continue the loop is x != 0. When all the 1 bits are shifted out of x the only thing left will be 0 bits. x will then equal 0.
The operation performed after each iteration is to right-shift the value in x by 1.
The if condition in the body of the loop performs bit-wise AND operation on x. The bit mask has a value of 1, which is an instance of the int value with all bits 0 except the lowest order bit. That AND operation will evaluate to 1 (or true in C) if the lowest order bit is 1, and to 0 (or false in C) if the lowest order bit is 0. The count of one bits is incremented if the if condition is true.
Related
I have to write code using only boolean operators such as follows to write code for a method that returns true or false if the number is negative or positive:
Bitwise AND (c = a & b), c has 1s in the places where both of the
corresponding bits in a and b are 1.
Bitwise OR (c = a | b), c has 1s wherever at least one of the
corresponding bits in a and b is 1.
Bitwise XOR (c = a ^ b), c has 1s wherever one and only one of the
corresponding bits in a and b is 1.
Bitwise NOT (c = ~a), c is a with each bit inverted.
Right shift (c = a >> b), c is a, with each bit moved lower b places.
Left shift (c = a << b), c is a, with each bit moved higher b places.
Boolean AND (c = a && b), c is 1 if both a and b are non-zero.
Boolean OR (c = a || b), c is 1 if either a and b are non-zero.
Boolean NOT (c = !a), c is 1 only if a is 0.
I have to finish this:
int isNegativeInt(int num) {
// something goes here
return num;
}
it should return 1 if true, that means num is a negative number
it should return 0 if false, that means num is a positive number
and I have to do the same thing for what's below:
int isNegativeLong(long num) {
// something goes here
return num;
}
int isNegativeChar(char num) {
// something goes here
return num;
}
Any ideas? Anything would help, thanks!
Given the assignment, I presume we are merely intended to test the high bit, perhaps assuming int is two’s complement. I also assume we cannot use INT_MIN or similar information (such as sizeof int) to know where the sign bit of an int is.
If we are allowed to use unsigned, then we can ascertain the high bit with unsigned H = -1u ^ -1u >> 1;. (This works because -1u is an unsigned value with all bits set, -1u >> 1 has all but the high bit set, and XORing them leaves just the high bit set.)
After that, num & H is non-zero if and only if the high bit in num is set. So we can return !!(num & H).
If we cannot use unsigned (perhaps the assignment is to write code that works for any signed integer type, not just int), then I expect the assignment is impossible using only the listed operators. To see this:
All of the bitwise operators (&, |, ^, and ~) operate on each bit independently, in parallel, and so they do not distinguish the high bit in any way and hence cannot be used to single out the high bit.
The logical operators (&& and ||) and ! operate on all bits condensed to a single bit. Again, they do not distinguish the high bit in any way and hence cannot be used to single out the high bit.
Thus, we are left with << and >>. These do distinguish the high and low bits, as they are boundaries for shifting bits in or out. However, if a number is negative, shifting it left is undefined, and shifting it right is implementation-defined. So we cannot write strictly conforming C code that shifts a value that we do not know is negative or not.
We could use the bitwise operators to clear various bits to produce a number we can safely shift, but, since those cannot distinguish the high bit, we cannot know when they have cleared the high bit to make the number safe for shifting. And we cannot generally know when they have not cleared the high bit (for example, we cannot write code that clears all bits but the high bit because, if we do not know where the high bit is, we do not know where the second highest is either).
Therefore, from the operations listed, there is none we can perform on a negative number to test its high bit.
I am writing a function with parameters:
int nbit2s(long int x, long int n){
}
I am looking to take in 64 bit number x, and find if a 2 bit representation of n bit length is possible. I am however restricted to using only bitwise operators and excluded from using operators such as >= <=, and conditional statements
For example, nbit2s(5,3) returns 0 because the representation is impossible.
I'm not looking for any code but just for ideas, so far my idea has been:
Take in number n and convert it to it's binary representation.
Left Shift the binary representation 64-n times to get MSB and store that in a variable shift
3.Shift to the right 64-n to get leading bit and store in shift
XOR original number with W, if 1 then TRUE, 0 then FALSE.
I feel like this is along the right lines, but if someone could explain perhaps a better way to do it or any mistakes i may have made, that would be great.
If I am understanding your question correctly, you would like to determine if the integer x can be represented as a binary number with n or less bits.
An easy way to test for this is to use the bitwise AND operator to mask out all bits above a maximum value, and then see if the masked integer is the same as the original.
Example:
bool nbit2s(uint64_t x, int n) {
return (x & (1ULL << n) - 1) == x;
}
A solution for positive numbers would be to just shift right by n. If it's still non-zero, then it needs more than n bits to represent it.
But since the argument is signed and you're talking about 2 complement representation, you'll probably have to cast it as unsigned representation to avoid sign extension.
This question already has answers here:
Arithmetic bit-shift on a signed integer
(6 answers)
Closed 9 years ago.
so, lets say I have a signed integer (couple of examples):
-1101363339 = 10111110 01011010 10000111 01110101 in binary.
-2147463094 = 10000000 00000000 01010000 01001010 in binary.
-20552 = 11111111 11111111 10101111 10111000 in binary.
now: -1101363339 >> 31 for example, should equal 1 right? but on my computer, I am getting -1. Regardless of what negative integer I pick if x = negative number, x >> 31 = -1. why? clearly in binary it should be 1.
Per C99 6.5.7 Bitwise shift operators:
If E1 has a signed type and a negative value, the resulting value is implementation-defined.
where E1 is the left-hand side of the shift expression. So it depends on your compiler what you'll get.
In most languages when you shift to the right it does an arithmetic shift, meaning it preserves the most significant bit. Therefore in your case you have all 1's in binary, which is -1 in decimal. If you use an unsigned int you will get the result you are looking for.
Per C 2011 6.5.7 Bitwise shift operators:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type
or if E1 has a signed type and a nonnegative value, the value of the result is the integral
part of the quotient of E1/ 2E2. If E1 has a signed type and a negative value, the
resulting value is implementation-defined.
Basically, the right-shift of a negative signed integer is implementation defined but most implementations choose to do it as an arithmetic shift.
The behavior you are seeing is called an arithmetic shift which is when right shifting extends the sign bit. This means that the MSBs will carry the same value as the original sign bit. In other words, a negative number will always be negative after a left shift operation.
Note that this behavior is implementation defined and cannot be guaranteed with a different compiler.
What you are seeing is an arithmetic shift, in contrast to the bitwise shift you were expecting; i.e., the compiler, instead of "brutally" shifting the bits, is propagating the sign bit, thus dividing by 2N.
When talking about unsigned ints and positive ints, a right shift is a very simple operation - the bits are shifted to the right by one place (inserting 0 on the left), regardless of their meaning. In such cases, the operation is equivalent to dividing by 2N (and actually the C standard defines it like that).
The distinction comes up when talking about negative numbers. Several negative numbers representation exist, although currently for integers most commonly 2's complement representation is used.
The problem of a "brutal" bitwise shift here is, for starters, that one of the bits is used in some way to express the sign; thus, shifting the binary digits regardless of the negative integers representation can give unexpected results.
For example, commonly in 2's representation the most significant bit is 1 for negative numbers, 0 for positive numbers; applying a bitwise shift (with zeroes inserted to the left) to a negative number would (between other things) make it positive, not resulting in the (usually expected) division by 2N
So, arithmetic shift is introduced; negative numbers represented in 2's complement have an interesting property: the division by 2N behavior of the shift is preserved if, instead of inserting zeroes from the left, you insert bits that have the same value of the original sign bit.
In this way, signed divisions by 2N can be performed with just a bit of extra logic in the shift, without having to resort to a fully-fledged division routine.
Now, is arithmetic shift guaranteed for signed integers? In some languages yes1, but in C it's not like that - the behavior of the shift operators when dealing with negative integers is left as an implementation-defined detail.
As often happens, this is due to different hardware support for the operation; C is used on vastly different platforms, and, especially in the past, there was quite a difference in the "cost" of operations depending on the platform.
For example, if the processor does not provide an arithmetic right shift instruction, the compiler would be mandated to emit a much slower DIV instruction of some kind, which could be a problem in an inner loop on slower processors. For these reasons, the C standard leaves it up to the implementor to do the most appropriate thing for the current platform.
In your case, your implementation probably chose arithmetic shift because you are running on an x86 processor, that uses 2's complement arithmetic and provides both bitwise and arithmetic shift as single CPU instructions.
Actually, languages like Java even have separated arithmetic and bitwise shift operators - this is mainly due to the fact that they do not have unsigned types to e.g. store bitfields.
This is a macro in the lwIP source code:
#define TCP_SEQ_LT(a,b) ((int32_t)((uint32_t)(a) - (uint32_t)(b)) < 0)
Which is used to check if a TCP sequence number is less than another, taking into account when the sequence numbers wrap around. It exploits the fact that arithmetic wraps around, but I am unable to understand how this works in this particular case.
Can anyone explain what happens and why the above works ?
Take a simple 4 bit integer example where a = 5 and b = 6. The binary representation of each will be
a = 0101
b = 0110
Now when we subtract these (or take two's complement of b, sum with a, and add 1), we get the following
0101
1001
+ 1
-----
1111
1111 is equal to 15 (unsigned) or -1 (signed, again translated using two's complement). By casting the two numbers to unsigned, we ensure that if b > a, the difference between the two is going to be a large unsigned number and have it's highest bit set. When translating this large unsigned number into its signed counterpart we will always get a negative number due to the set MSB.
As nos pointed out, when a sequence number wraps around from the max unsigned value back to the min, the macro will also return that the max value is < min using the above arithmetic, hence its usefulness.
On wrap-around a will be much greater than b. If we subtract them the result will also be very large, ie have its high-order bit set. If we then treat the result as a signed value the large difference will turn into a negative number, less than 0.
If you had 2 sequence numbers 2G apart it wouldn't work, but that's not going to happen.
Because it is first cast as a signed integer before it is compared to zero. Remember that the first bit reading from left to right determines the sign in a signed number but is used to increase the unsigned int's range by an extra bit.
Example: let's say you have a 4 bit unsigned number. This would mean 1001 is 17. But as a signed integer this would be -1.
Now lets say we did b0010 - b0100. This ends up with b1110. Unsigned this is 14, and signed this is -6.
This is a doubt regarding the representation of bits of signed integers. For example, when you want to represent -1, it is equivalent to 2's complement of (+1). So -1 is represented as 0xFFFFFFF. Now when I shift my number by 31 and print the result it is coming back as -1.
signed int a = -1;
printf(("The number is %d ",(a>>31));//this prints as -1
So can anyone please explain to me how the bits are represented for negative numbers?
Thanks.
When the top bit is zero, the number is positive. When it's 1, the number is negative.
Negative numbers shifted right keep shifting a "1" in as the topmost bit to keep the number negative. That's why you're getting that answer.
For more about two's complement, see this Stackoverflow question.
#Stobor points out that some C implementations could shift 0 into the high bit instead of 1. [Verified in Wikipedia.] In Java it's dependably an arithmetic shift.
But the output given by the questioner shows that his compiler is doing an arithmetic shift.
The C standard leaves it undefined whether the right shift of a negative (necessarily signed) integer shifts zeroes (logical shift right) or sign bits (arithmetic shift right) into the most significant bit. It is up to the implementation to choose.
Consequently, portable code ensures that it does not perform right shifts on negative numbers. Either it converts the value to the corresponding unsigned value before shifting (which is guaranteed to use a logical shift right, putting zeroes into the vacated bits), or it ensures that the value is positive, or it tolerates the variation in the output.
This is an arithmetic shift operation which preserves the sign bit and shifts the mantissa part of a signed number.
cheers
Basically there are two types of right shift. An unsigned right shift and a signed right shift. An unsigned right shift will shift the bits to the right, causing the least significant bit to be lost, and the most significant bit to be replaced with a 0. With a signed right shift, the bits are shifted to the right, causing the least significant bit be be lost, and the most significant bit to be preserved. A signed right shift divides the number by a power of two (corresponding to the number of places shifted), whereas an unsigned shift is a logical shifting operation.
The ">>" operator performs an unsigned right shift when the data type on which it operates is unsigned, and it performs a signed right shift when the data type on which it operates is signed. So, what you need to do is cast the object to an unsigned integer type before performing the bit manipulation to get the desired result.
Have a look at two's complement description. It should help.
EDIT: When the below was written, the code in the question was written as:
unsigned int a = -1;
printf(("The number is %d ",(a>>31));//this prints as -1
If unsigned int is at least 32 bits wide, then your compiler isn't really allowed to produce -1 as the output of that (with the small caveat that you should be casting the unsigned value to int before you pass it to printf).
Because a is an unsigned int, assigning -1 to it must give it the value of UINT_MAX (as the smallest non-negative value congruent to -1 modulo UINT_MAX+1). As long as unsigned int has at least 32 bits on your platform, the result of shifting that unsigned quantity right by 31 will be UINT_MAX divided by 2^31, which has to fit within int. (If unsigned int is 31 bits or shorter, it can produce whatever it likes because the result of the shift is unspecified).