Convert signed 13-bit value to signed 16-bit - bit-manipulation

Is there a prettier way of doing a conversion from a signed 13-bit value to a signed 16-bit value than what i've got below? Both values lies in 16 bit words, the 13-bit value being shifted 3 bits.
S = Sign, O = Value bit, X = Unused
a is the signed 13-bit | SOOO OOOO OOOO OXXX
b is the signed 16-bit | SOOO OOOO OOOO OOOO
Current implementation
b = a & 0x7FF8; // Remove sign XOOO OOOO OOOO OXXX
b = b >> 3; // Shift value 3 bit XXXO OOOO OOOO OOOO
b = b | (a & 0x8000); // Add sign SXXO OOOO OOOO OOOO

Right shift on signed types is implementation defined (in C, at least - you didn't actually mention what language you're using here), but assuming your compiler is like 99% of other compilers and does an arithmetic right shift on signed values then all you need is:
b = a >> 3; // Syyy yyyy yyyy yxxx => SSSS yyyy yyyy yyyy
Obviously you should test this and/or check your compiler documentation.
[Note also that this assumes that we're talking about 2's complement representation for the values - again it's not specified in your question.]

Related

Finding the next power of 2 for a negative number

Hey guys I was doing research on calculating the next power of two and stumbled on a code that looks like this:
int x;//assume that x is already initialized with a value
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x+1;
It works fine when I run with positive numbers but it doesn't work with negative numbers which I dont understand because I think it should not matter whether or not a number is positive or negative in terms of finding the next power of two for it. If we have the number 5 and we want to find the next power of 2. If we think about it intuitively we know that its 8 because 8 is bigger than 5 and 8 is the same as 2^3. If I try using a negative number I always keep getting 0 which I don't understand because 0 is not a power of two
The short answer is because the C++ standard states that the value resulting from the >> operator on negative values is implementation defined, whereas on positive values it has a result of dividing by a power of 2.
The term "implementation defined", over-simplistically, means that the standard permits the result to vary between implementations i.e. between compilers. Among other things, that means no guarantee that it will behave in the same way as for positive values (for which the behaviour is unambiguously specified).
The reason is that the representation of a signed int is also implementation-defined. This allows, for example, the usage of twos-complement representation - which (although other representations are used sometimes) is quite commonly used in practice.
Mathematically, a right shift in twos-complement is equivalent to division by a power of two with rounding down toward -infinity, not toward zero. For a positive value, rounding toward zero and toward -infinity have the same effect (both zero and -infinity are less than any positive integral value). For a negative value they do not (rounding is away from zero, not toward zero).
Peter gave you an interpretation of the code based on towards which value you round. Here's another, more bitwise, one:
The successive shifts in this code are "filling in" with 1s all bit positions lower than the highest one set at the start. Let us look at that more in detail:
Let x=0b0001 ???? ???? ???? be the binary representation of a 16 bit number, where ? may be 0 or 1.
x |= x >> 1; // x = 0b0001 ???? ???? ???? | 0b0000 1??? ???? ???? = 0b0001 1??? ???? ????
x |= x >> 2; // x = 0b0001 1??? ???? ???? | 0b0000 011? ???? ???? = 0b0001 111? ???? ????
x |= x >> 4; // x = 0b0001 111? ???? ???? | 0b0000 0001 111? ???? = 0b0001 1111 111? ????
x |= x >> 8; // x = 0b0001 1111 111? ???? | 0b0000 0000 0001 1111 = 0b0001 1111 1111 1111
Hence the shifts are giving you the number of the form 0b00...011...1 that is only 0s then only 1s, which means a number of the form 2^n-1. That is why you add 1 at the end, to get a power of 2. To get the correct result, you also need to remove 1 at the start, to compensate for the one you'll add at the end.
Now for negative numbers, the C++ standard does not define what the most significant bits should be when right-shifting. But whether they are 1 or 0 is irrelevant in this specific case, as long as your representation of negative numbers uses a 1 in its most significant bit position, i.e. for almost all of them.*
Because you always or x with itself, all those left-most bits (where the shifts differ) are going to be ored with 1s. At the end of the algorithm, you will return 0b11111...1 + 1 which in your case means 0 (because you use 2s complement, the result would be 1 in 1s complement and -2number of bits - 1 + 1 in sign-magnitude).
* This holds true for the main negative numbers representations, from most to least popular: that is, 2s complement, sign-magnitude, and 1s complement. An example where this is not true is excess-K representation, which is used for IEEE floating point exponents.

why does bitwise shift replace date with 1s instead of 0 here?

For a program utilising bitmasks I desired to write numbers in binary... i.e To copy the first 8 bits of x to z, I write
y = 0xff000000;
z = 0;
z = (y & x) | z
Where x, y, z are all int. Now using left shift and right shift operators I wanted to move 1s of y right or left to bitmask another set of bits, so I write the following code
cout<< bitset<32>(y>>10) <<"\n" << bitset<32>(y<<10) <<endl;
Now what I expected as output was:
00000000001111111100000000000000
00000000000000000000000000000000
but I got:
11111111111111111100000000000000
00000000000000000000000000000000
Why are the new bits '1' intead of '0' on first line of output?
How can I change current output to desired output?
y is a signed integer. In signed integers, the topmost bit is the sign bit, and when you right-shift signed integers the topmost bit propagates.
Using eight-bit values: -4 is
11111100
What do you think makes sense, when you right shift -4?
Do you expect to get -2:
11111110
Or do you expect to get 126?
01111110
Remember that a left shift is an equivalent to multiplying by 2, so a right shift is equivalent to dividing by 2 (and discarding the remainder).
If you want to shift a signed integer, and get unsigned integer semantics, cast it to an unsigned integer, first.

NOT operation on integer value

I knew that ~ operator does NOT operation. But I could not make out the output of the following program (which is -65536). What exactly is happening?
#include <stdio.h>
int main(void) {
int b = 0xFFFF;
printf("%d",~b);
return 0;
}
Assuming 32-bit integers
int b = 0xFFFF; => b = 0x0000FFFF
~b = 0xFFFF0000
The top bit is now set. Assuming 2s complement, this means we have a negative number. Inverting the other bits then adding one gives 0x00010000 or 65536
When you assign the 16-bit value 0xffff to the 32-bit integer b, the variable b actually becomes 0x0000ffff. This means when you do the bitwise complement it becomes 0xffff0000 which is the same as decimal -65536.
The ~ operator in C++ is the bitwise NOT operator. It is also called the bitwise complement. This is flipping the bits of your signed integer.
For instance, if you had
int b = 8;
// b in binary = 1000
// ~b = 0111
This will flip the bits that represent the initial integer value provided.
It is doing a bitwise complement, this output may help you understand what is going on better:
std::cout << std::hex << " b: " << std::setfill('0') << std::setw(8) << b
<< " ~b: " << (~b) << " -65536: " << -65536 << std::endl ;
the result that I receive is as follows:
b: 0000ffff ~b: ffff0000 -65536: ffff0000
So we are setting the lower 16 bits to 1 which gives us 0000ffff and then we do a complement which will set the lower 16 bits to 0 and the upper 16 bits to 1 which gives us ffff0000 which is equal to -65536 in decimal.
In this case since we are working with bitwise operations, examining the data in hex gives us some insight into what is going on.
The result depends on how signed integers are represented on your platform. The most common representation is a 32-bit value using "2s complement" arithmetic to represent negative values. That is, a negative value -x is represented by the same bit pattern as the unsigned value 2^32 - x.
In this case, the original bit pattern has the lower 16 bits set:
0x0000ffff
The bitwise negation clears those bits and sets the upper 16 bits:
0xffff0000
Interpreting this as a negative number gives the value -65536.
Usually, you'll want to use unsigned types when you're messing around with bitwise arithmetic, to avoid this kind of confusion.
Your comment:
If it is NOT of 'b' .. then output should be 0 but why -65536
Suggests that you are expecting the result of:
uint32_t x = 0xFFFF;
uint32_t y = ~x;
to be 0.
That would be true for a logical not operation, such as:
uint32_t x = 0xFFFF;
uint32_t y = !x;
...but operator~ is not a logical NOT, but a bitwise not. There is a big difference.
A logical returns 0 for non-0 values (or false for true values), and 1 for 0 values.
But a bitwise not reverses each bit in a given value. So a binary NOT of 0xF:
0x0F: 00000000 11111111
~0x0F: 11111111 00000000
Is not zero, but 0xF0.
For every binary number in the integer, a bitwise NOT operation turns all 1s into 0s, and all 0s are turned to 1s.
So hexadecimal 0xFFFF is binary 1111 1111 1111 1111 (Each hexadecimal character is 4 bits, and F, being 15, is full 1s in all four bits)
You set a 32 bit integer to that, which means it's now:
0000 0000 0000 0000 1111 1111 1111 1111
You then NOT it, which means it's:
1111 1111 1111 1111 0000 0000 0000 0000
The topmost bit is the signing bit (whether it's positive or negative), so it gives a negative number.

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.

Right shift with zeros at the beginning

I'm trying to do a kind of left shift that would add zeros at the beginning instead of ones. For example, if I left shift 0xff, I get this:
0xff << 3 = 11111000
However, if I right shift it, I get this:
0xff >> 3 = 11111111
Is there any operation I could use to get the equivalent of a left shift? i.e. I would like to get this:
00011111
Any suggestion?
Edit
To answer the comments, here is the code I'm using:
int number = ~0;
number = number << 4;
std::cout << std::hex << number << std::endl;
number = ~0;
number = number >> 4;
std::cout << std::hex << number << std::endl;
output:
fffffff0
ffffffff
Since it seems that in general it should work, I'm interested as to why this specific code doesn't. Any idea?
This is how C and binary arithmetic both work:
If you left shift 0xff << 3, you get binary: 00000000 11111111 << 3 = 00000111 11111000
If you right shift 0xff >> 3, you get binary: 00000000 11111111 >> 3 = 00000000 00011111
0xff is a (signed) int with the positive value 255. Since it is positive, the outcome of shifting it is well-defined behavior in both C and C++. It will not do any arithmetic shifts nor any kind or poorly-defined behavior.
#include <stdio.h>
int main()
{
printf("%.4X %d\n", 0xff << 3, 0xff << 3);
printf("%.4X %d\n", 0xff >> 3, 0xff >> 3);
}
Output:
07F8 2040
001F 31
So you are doing something strange in your program because it doesn't work as expected. Perhaps you are using char variables or C++ character literals.
Source: ISO 9899:2011 6.5.7.
EDIT after question update
int number = ~0; gives you a negative number equivalent to -1, assuming two's complement.
number = number << 4; invokes undefined behavior, since you left shift a negative number. The program implements undefined behavior correctly, since it either does something or nothing at all. It may print fffffff0 or it may print a pink elephant, or it may format the hard drive.
number = number >> 4; invokes implementation-defined behavior. In your case, your compiler preserves the sign bit. This is known as arithmetic shift, and arithmetic right shift works in such a way that the MSB is filled with whatever bit value it had before the shift. So if you have a negative number, you will experience that the program is "shifting in ones".
In 99% of all real world cases, it doesn't make sense to use bitwise operators on signed numbers. Therefore, always ensure that you are using unsigned numbers, and that none of the dangerous implicit conversion rules in C/C++ transforms them into signed numbers (for more info about dangerous conversions, see "the integer promotion rules" and "the usual arithmetic conversions", plenty of good info about those on SO).
EDIT 2, some info from the C99 standard's rationale document V5.10:
6.5.7 Bitwise shift operators
The description of shift operators in K&R suggests that shifting by a
long count should force the left operand to be widened to long before
being shifted. A more intuitive practice, endorsed by the C89
Committee, is that the type of the shift count has no bearing on the
type of the result.
QUIET CHANGE IN C89
Shifting by a long count no longer coerces the shifted operand to
long. The C89 Committee affirmed the freedom in implementation granted
by K&R in not requiring the signed right shift operation to sign
extend, since such a requirement might slow down fast code and since
the usefulness of sign extended shifts is marginal. (Shifting a
negative two’s complement integer arithmetically right one place is
not the same as dividing by two!)
If you explicitly shift 0xff it works as you expected
cout << (0xff >> 3) << endl; // 31
It should be possible only if 0xff is in type of signed width 8 (char and signed char on popular platforms).
So, in common case:
You need to use unsigned ints
(unsigned type)0xff
right shift works as division by 2(with rounding down, if I understand correctly).
So when you have 1 as first bit, you have negative value and after division it's negative again.
The two kinds of right shift you're talking about are called Logical Shift and Arithmetic Shift. C and C++ use logical shift for unsigned integers and most compilers will use arithmetic shift for a signed integer but this is not guaranteed by the standard meaning that the value of right shifting a negative signed int is implementation defined.
Since you want a logical shift you need to switch to using an unsigned integer. You can do this by replacing your constant with 0xffU.
To explain your real code you just need the C++ versions of the quotes from the C standard that Lundin gave in comments:
int number = ~0;
number = number << 4;
Undefined behavior. [expr.shift] says
The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated
bits are zero-filled. If E1 has an unsigned type, the value of the
result is E1 × 2E2, reduced modulo one more than the maximum value
representable in the result type. Otherwise, if E1 has a signed type
and non-negative value, and E1×2E2 is representable in the result
type, then that is the resulting value; otherwise, the behavior is
undefined.
number = ~0;
number = number >> 4;
Implementation-defined result, in this case your implementation gave you an arithmetic shift:
The value 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 non-negative 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
You should use an unsigned type:
unsigned int number = -1;
number = number >> 4;
std::cout << std::hex << number << std::endl;
Output:
0x0fffffff
To add my 5 cents worth here...
I'm facing exactly the same problem as this.lau! I've done some perfunctory research on this and these are my results:
typedef unsigned int Uint;
#define U31 0x7FFFFFFF
#define U32 0xFFFFFFFF
printf ("U31 right shifted: 0x%08x\n", (U31 >> 30));
printf ("U32 right shifted: 0x%08x\n", (U32 >> 30));
Output:
U31 right shifted: 0x00000001 (expected)
U32 right shifted: 0xffffffff (not expected)
It would appear (in the absence of anyone with detailed knowledge) that the C compiler in XCode for Mac OS X v5.0.1 reserves the MSB as a carry bit that gets pulled along with each shift.
Somewhat annoyingly, the converse is NOT true:-
#define ST00 0x00000001
#define ST01 0x00000002
printf ("ST00 left shifted: 0x%08x\n", (ST00 << 30));
printf ("ST01 left shifted: 0x%08x\n", (ST01 << 30));
Output:
ST00 left shifted: 0x40000000
ST01 left shifted: 0x80000000
I concur completely with the people above that assert that the sign of the operand has no bearing on the behaviour of the shift operator.
Can anyone shed any light on the specification for the Posix4 implementation of C? I feel a definitive answer may rest there.
In the meantime, it appears that the only workaround is a construct along the following lines;-
#define CARD2UNIVERSE(c) (((c) == 32) ? 0xFFFFFFFF : (U31 >> (31 - (c))))
This works - exasperating but necessary.
Just in case if you want the first bit of negative number to be 0 after right shift what we can do is to take the XOR of that negative number with INT_MIN that will make its msb zero, I understand that its not appropriate arithmetic shift but will get work done