Multiply with negative integer just by shifting - c

I'm trying to find a way to multiply an integer value with negative value just with bit shifting.
Usually I do this by shifting with the power of 2 which is closest to my factor and just adding / subtracting the rest, e.g. x * 7 = ((x << 3) - x)
Let's say I'd want to calculate x * -112. The only way I can imagine is -((x << 7) - (x << 4), so to calculate x * 112 and negate it afterwards.
Is there a "prettier" way to do this?

Get the compiler to do it, then check the produced assembly.

The negative of a positive number in 2's complement is done by negating all the bits and then adding 1 to the result. For example, to get -4 from 4 you would do:
4 = 000...0100 in binary. ~4 = 111...1011. -4 = 111...1100.
Same to reverse the sign.
So you could do this:
(~((x << 7) - (x << 4))) + 1.
Not necessarily prettier, but faster if we consider bitwise operations faster than arithmetic operations (especially multiplication) and ignore compiler optimizations.
Not that I'm saying you should do this, because you shouldn't. It's good to know about it though.

Computers internally represent negative integers in two's compliment form. One of the nice properties of two's compliment arithmetic is that multiply negative numbers is just like multiplying positive numbers. Hence, find the two's complement and use your normal approach.
Here's a simple example. For ease of exposition, I'm going to using 8-bit integers and multiply by -15.
15 in hex is 0x0f. The two's compliment of 0x0f is 0xf1.
Since these are 8-bit integers, all arithmetic is mod 0xff. In particular, note that 0x100 * anything = 0.
x * 0xf1
= x * (0x100 - 0x10 + 0x01)
= -(x * 0x10) + x
= -(x << 4) + x

Related

Understanding Byte swapping

I'm trying to figure out a way to create a little endian/big endian conversion for 64 bit integers (uint64_t) and while I find a lot of answers online as to how to do it, none of them explain what exactly is going on. For example, to get the nth byte of the integer I found this response:
int x = (number >> (8*n)) & 0xff;
Even though I understand the bit shifting component (shifting 8n digits to the right) I don't see where the & and 0xff come in, and what they mean aside from & is a bitwise AND operator.
So, how would this sort of logic apply to a big-endian/little-endian byte swapping method for 64 bit integers?
Thank you in advance.
It might be easiest to think of an analogy with decimal numbers:
Take the number 308. It has three digits, '3', '0', and '8'. By convention, digits to the left are more significant than digits to the right. But the convention could just as easily have been the other way...the digits could've been written in reverse order (e.g., 803).
Why is this relevant? Consider a hexadecimal representation of a number on a computer: 0xabcd0123. In a mathematically rigorous sense, one can view this number as 4 radix-256 digits. (i.e., 0xab, 0xcd, 0x01, 0x23). So, endianness is about the convention by which these radix-256 digits are ordered when written into memory.
Little-endian means "write the least significant digit to the lowest address";
Big-endian means "write the most significant digit to the lowest address".
So, on to the mechanics of processing endianness:
If you think of the decimal example above, how would you get each digit? The least significant digit is given by taking the number modulo 10 (i.e., 308 % 10 = 8). The second digit can be found by dividing the number by 10, then taking it modulo 10 (i.e., 308 / 10 = 30; 30 % 10 = 0) and so forth.
The process is exactly the same for binary data on a computer, except that it's treated as radix-256 instead of radix-10 like decimal digits. This is where a few tricks come in.
When doing modulo with a modulus that is a power of 2, you can do it via AND. Let m=256 as our modulus. Because m = 2 to some power, x % m is equivalent to x & (m-1). This is a numerical fact that is out-of scope for this answer.
When doing division by a power of 2, you can do it via right-shift. That is, let m=256 be our divisor. Because m = 2 to the 8th power, x / m is equivalent to x >> 8.
Thus binary endian-specific serialization uses exactly the process above:
uint32_t val = 0xabcd0123;
(val & 0xff) is equivalent to (val % 256), and yields 0x23.
((val >> 8) & 0xff) is equivalent to ((val / 256) % 256), and yields 0x01.
((val >> 16) & 0xff) is equivalent to (((val / 256)/256) % 256), and yields 0xcd.
and so on. So now that you have access to the digits/bytes, you simply have to chose the order in which to store them. Per above, "big endian = most-significant at lowest address", "little endian = least-significant at lowest address".

Divide a signed integer by a power of 2

I'm working on a way to divide a signed integer by a power of 2 using only binary operators (<< >> + ^ ~ & | !), and the result has to be round toward 0. I came across this question also on Stackoverflow on the problem, however, I cannot understand why it works. Here's the solution:
int divideByPowerOf2(int x, int n)
{
return (x + ((x >> 31) & ((1 << n) + ~0))) >> n;
}
I understand the x >> 31 part (only add the next part if x is negative, because if it's positive x will be automatically round toward 0). But what's bothering me is the (1 << n) + ~0 part. How can it work?
Assuming 2-complement, just bit-shifting the dividend is equivalent to a certain kind of division: not the conventional division where we round the dividend to next multiple of divisor toward zero. But another kind where we round the dividend toward negative infinity. I rediscovered that in Smalltalk, see http://smallissimo.blogspot.fr/2015/03/is-bitshift-equivalent-to-division-in.html.
For example, let's divide -126 by 8. traditionally, we would write
-126 = -15 * 8 - 6
But if we round toward infinity, we get a positive remainder and write it:
-126 = -16 * 8 + 2
The bit-shifting is performing the second operation, in term of bit patterns (assuming 8 bits long int for the sake of being short):
1000|0010 >> 3 = 1111|0000
1000|0010 = 1111|0000 * 0000|1000 + 0000|0010
So what if we want the traditional division with quotient rounded toward zero and remainder of same sign as dividend? Simple, we just have to add 1 to the quotient - if and only if the dividend is negative and the division is inexact.
You saw that x>>31 corresponds to first condition, dividend is negative, assuming int has 32 bits.
The second term corresponds to the second condition, if division is inexact.
See how are encoded -1, -2, -4, ... in two complement: 1111|1111 , 1111|1110 , 1111|1100. So the negation of nth power of two has n trailing zeros.
When the dividend has n trailing zeros and we divide by 2^n, then no need to add 1 to final quotient. In any other case, we need to add 1.
What ((1 << n) + ~0) is doing is creating a mask with n trailing ones.
The n last bits don't really matter, because we are going to shift to the right and just throw them away. So, if the division is exact, the n trailing bits of dividend are zero, and we just add n 1s that will be skipped. On the contrary, if the division is inexact, then one or more of the n trailing bits of the dividend is 1, and we are sure to cause a carry to the n+1 bit position: that's how we add 1 to the quotient (we add 2^n to the dividend). Does that explain it a bit more?
This is "write-only code": instead of trying to understand the code, try to create it by yourself.
For example, let's divide a number by 8 (shift right by 3).
If the number is negative, the normal right-shift rounds in the wrong direction. Let's "fix" it by adding a number:
int divideBy8(int x)
{
if (x >= 0)
return x >> 3;
else
return (x + whatever) >> 3;
}
Here you can come up with a mathematical formula for whatever, or do some trial and error. Anyway, here whatever = 7:
int divideBy8(int x)
{
if (x >= 0)
return x >> 3;
else
return (x + 7) >> 3;
}
How to unify the two cases? You need to make an expression that looks like this:
(x + stuff) >> 3
where stuff is 7 for negative x, and 0 for positive x. The trick here is using x >> 31, which is a 32-bit number whose bits are equal to the sign-bit of x: all 0 or all 1. So stuff is
(x >> 31) & 7
Combining all these, and replacing 8 and 7 by the more general power of 2, you get the code you asked about.
Note: in the description above, I assume that int represents a 32-bit hardware register, and hardware uses two's complement representation to do right shift.
OP's reference is of a C# code and so many subtle differences that cause it to be bad code with C, as this post is tagged.
int is not necessarily 32-bits so using a magic number of 32 does not make for a robust solution.
In particular (1 << n) + ~0 results in implementation defined behavior when n causes a bit to be shifted into the sign place. Not good coding.
Restricting code to only using "binary" operators << >> + ^ ~ & | ! encourages a coder to assume things about int which is not portable nor compliant with the C spec. So OP's posted code does not "work" in general, although may work in many common implementations.
OP code fails when int is not 2's complement, not uses the range [-2147483648 .. 2147483647] or when 1 << n uses implementation behavior that is not as expected.
// weak code
int divideByPowerOf2(int x, int n) {
return (x + ((x >> 31) & ((1 << n) + ~0))) >> n;
}
A simple alternative, assuming long long exceeds the range of int follows. I doubt this meets some corner of OP's goals, but OP's given goals encourages non-robust coding.
int divideByPowerOf2(int x, int n) {
long long ill = x;
if (x < 0) ill = -ill;
while (n--) ill >>= 1;
if (x < 0) ill = -ill;
return (int) ill;
}

How to convert from sign-magnitude to two's complement

How would I convert from sign-magnitude to two's complement. I don't know where to start. Any help would be appreciated.
I can only use the following operations:!,~,|,&,^,+,>>,<<.
/*
* sm2tc - Convert from sign-magnitude to two's complement
* where the MSB is the sign bit
* Example: sm2tc(0x80000005) = -5.
*
*/
int sm2tc(int x) {
return 2;
}
You can convert signed-magnitude to two's complement by subtracting the number from 0x80000000 if the number is negative. This will work for a 32-bit integer on a machine using two's complement to represent negative values, but if the value is positive this will result in a two's complement negation. A right shift of a two's complement negative number will shift in one's, we can utilize this to make a mask to select between the original value, or the conversion of a signed-magnitude negative value to a two's complement negative value.
int sm2tc(int x) {
int m = x >> 31;
return (~m & x) | (((x & 0x80000000) - x) & m);
}
There you go.
uint32_t sm2tc(uint32_t x)
{
return (x & 0x80000000)
? ((~(x & 0x7fffffff)) + (uint32_t)1)
: x;
}
Interestingly, the conversion between the two formats is symmetrical, so you need only one conversion function to swap from one format to the other. Here is the complete conversion without relying on any conditionals:
uint32_t convertSignRepresentation(uint32_t in) {
uint32_t mask = -(in >> 31);
return mask&0x80000000-in | ~mask&in;
}
The technique I used here is essentially replacing the conditional operator in
uint32_t convertSignRepresentation(uint32_t in) {
return (in >> 31) ? 0x80000000-in : in;
}
by a bitmask of only zeros or ones to select the correct resulting value.
Please note, that 0x80000000 (either smallest possible value, or negative zero) is projected to positive zero, and cannot be recovered. So convertSignRepresentation(converSignRepresentation(0x80000000)) yields zero instead of 0x80000000. This might give nasty surprises. It might be avoided in theory by mapping 0x80000000 onto itself, but that is not as easy to do and has even nastier surprises...
Edit:
A comment pointed out that subtraction was not on the list of allowed operators, even though addition is. I don't know whether this was deliberate or a mistake. Anyways, the operation -x can be written as ~x + 1. With this, the code becomes:
uint32_t convertSignRepresentation(uint32_t in) {
uint32_t mask = ~(in >> 31) + 1;
return mask&0x80000001+~in | ~mask&in;
}
Signed Numbers are 8 bit quantities with the least significant 7 bits representing the magnitude and the most significant bit indicating the sign. 0 in this bit indicates the number is positive, and 1 indicates it is negative. There is no magnitude information in this 8th bit-just the sign.
To convert a negative signed number to two's complement, first set the 8th bit to zero. Then invert all 8 bits. Finally add 1. An example follows:
Signed Number:
10001111
set the 8th bit to zero: (use & operator)
00001111
invert all 8 bits: (use bitwise-complement operator)
11110000
finally, add 1; resulting in the final two's complement number: (use + operator)
11110001
If the 8th bit is 0, indicating that the signed number is positive, the number requires no conversion. It's two's complement representation is the same as the signed magnitude representation.
To convert from Sign Magnitude x to Two's Complement y:
1) On a two's complement machine.
2) Use only !,~,|,&,^,+,>>,<<
3) Does not use ?:, -, *, /
4) Does not assume 4-byte int
5) Work with all Sign Magnitude including +0 and -0
#include <limits.h>
int sm2tc(int x) {
int sign = x & INT_MIN;
int negmask = UINT_MAX + !sign;
return (x & ~negmask) | (negmask & ((~x + 1)^INT_MIN));
}

What does >> and 0xfffffff8 mean?

I was told that (i >> 3) is faster than (i/8) but I can't find any information on what >> is. Can anyone point me to a link that explains it?
The same person told me "int k = i/8, followed by k*8 is better accomplished by (i&0xfffffff8);" but again Google didn't help m...
Thanks for any links!
As explained here the >> operator is simply a bitwise shift of the bits of i. So shifting i 1 bit to the right results in an integer-division by 2 and shifting by 3 bits results in a division by 2^3=8.
But nowadays this optimization for division by a power of two should not really be done anymore, as compilers should be smart enough to do this themselves.
Similarly a bitwise AND with 0xFFFFFFF8 (1...1000, last 3 bits 0) is equal to rounding down i to the nearest multiple of 8 (like (i/8)*8 does), as it will zero the last 3 bits of i.
Bitwise shift right.
i >> 3 moves the i integer 3 places to the right [binary-way] - aka, divide by 2^3.
int x = i / 8 * 8:
1) i / 8, can be replaced with i >> 3 - bitwise shift to the right on to 3 digits (8 = 2^3)
2) i & xfffffff8 comparison with mask
For example you have:
i = 11111111
k (i/8) would be: 00011111
x (k * 8) would be: 11111000
Therefore the operation just resets last 3 bits:
And comparable time cost multiplication and division operation can be rewritten simple with
i & xfffffff8 - comparison with (... 11111000 mask)
They are Bitwise Operations
The >> operator is the bit shift operator. It takes the bit represented by the value and shifts them over a set number of slots to the right.
Regarding the first half:
>> is a bit-wise shift to the right.
So shifting a numeric value 3 bits to the right is the same as dividing by 8 and inting the result.
Here's a good reference for operators and their precedence: http://web.cs.mun.ca/~michael/c/op.html
The second part of your question involves the & operator, which is a bit-wise AND. The example is ANDing i and a number that leaves all bits set except for the 3 least significant ones. That is essentially the same thing happening when you have a number, divide it by 8, store the result as an integer, then multiply that result by 8.
The reason this is so is that dividing by 8 and storing as an integer is the same as bit-shifting to the right 3 places, and multiplying by 8 and storing the result in an int is the same as bit-shifting to the left 3 places.
So, if you're multiplying or dividing by a power of 2, such as 8, and you're going to accept the truncating of bits that happens when you store that result in an int, bit-shifting is faster, operationally. This is because the processor can skip the multiply/divide algorithm and just go straight to shifting bits, which involves few steps.
Bitwise shifting.
Suppose I have an 8 -bit integer, in binary
01000000
If I left shift (>> operator) 1 the result is
00100000
If I then right shift (<< operator) 1, I clearly get back to wear I started
01000000
It turns out that because the first binary integer is equivelant to
0*2^7 + 1*2^6 + 0*2^5 + 0*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 0*2^0
or simply 2^6 or 64
When we right shift 1 we get the following
0*2^7 + 0*2^6 + 1*2^5 + 0*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 0*2^0
or simply 2^5 or 32
Which means
i >> 1
is the same as
i / 2
If we shift once more (i >> 2), we effectively divide by 2 once again and get
i / 2 / 2
Which is really
i / 4
Not quite a mathematical proof, but you can see the following holds true
i >> n == i / (2^n)
That's called bit shifting, it's an operation on bits, for example, if you have a number on a binary base, let's say 8, it will be 1000, so
x = 1000;
y = x >> 1; //y = 100 = 4
z = x >> 3; //z = 1
Your shifting the bits in binary so for example:
1000 == 8
0100 == 4 (>> 1)
0010 == 2 (>> 2)
0001 == 1 (>> 3)
Being as you're using a base two system, you can take advantage with certain divisors (integers only!) and just bit-shift. On top of that, I believe most compilers know this and will do this for you.
As for the second part:
(i&0xfffffff8);
Say i = 16
0x00000010 & 0xfffffff8 == 16
(16 / 8) * 8 == 16
Again taking advantage of logical operators on binary. Investigate how logical operators work on binary a bit more for really clear understanding of what is going on at the bit level (and how to read hex).
>> is right shift operation.
If you have a number 8, which is represented in binary as 00001000, shifting bits to the right by 3 positions will give you 00000001, which is decimal 1. This is equivalent to dividing by 2 three times.
Division and multiplication by the same number means that you set some bits at the right to zero. The same can be done if you apply a mask. Say, 0xF8 is 11111000 bitwise and if you AND it to a number, it will set its last three bits to zero, and other bits will be left as they are. E.g., 10 & 0xF8 would be 00001010 & 11111000, which equals 00001000, or 8 in decimal.
Of course if you use 32-bit variables, you should have a mask fitting this size, so it will have all the bits set to 1, except for the three bits at the right, giving you your number - 0xFFffFFf8.
>> shifts the number to the right. Consider a binary number 0001000 which represents 8 in the decimal notation. Shifting it 3 bits to the right would give 0000001 which is the number 1 in decimal notation. Thus you see that every 1 bit shift to the right is in fact a division by 2. Note here that the operator truncates the float part of the result.
Therefore i >> n implies i/2^n.
This might be fast depending on the implementation of the compiler. But it generally takes place right in the registers and therefore is very fast as compared to traditional divide and multiply.
The answer to the second part is contained in the first one itself. Since division also truncates all the float part of the result, the division by 8 will in theory shift your number 3 bits to the right, thereby losing all the information about the rightmost 3 bits. Now when you again multiply it by 8 (which in theory means shifting left by 3 bits), you are padding the righmost 3 bits by zero after shifting the result left by 3 bits. Therefore, the complete operation can be considered as one "&" operation with 0xfffffff8 which means that the number has all bits 1 except the rightmost 4 bits which are 1000.

Bitshift to multiply by any number

Using only adding, subtracting, and bitshifting, how can I multiply an integer by a given number?
For example, I want to multiply an integer by 17.
I know that shifting left is multiplying by a multiple of 2 and shifting right is dividing by a power of 2 but I don’t know how to generalize that.
What about negative numbers? Convert to two's complement and do the same procedure?
(EDIT: OK, I got this, nevermind. You convert to two's complement and then do you shifting according to the number from left to right instead of right to left.)
Now the tricky part comes in. We can only use 3 operators.
For example, multiplying by 60 I can accomplish by using this:
(x << 5) + (x << 4) + (x << 3) + (x << 2)
Where x is the number I am multiplying. But that is 7 operators - how can I condense this to use only 3?
It's called shift-and-add. Wikipedia has a good explanation of this:
http://en.wikipedia.org/wiki/Multiplication_algorithm#Shift_and_add
EDIT:
To answer your other question, yes converting to two's compliment will work. But you need to sign extend it long enough to hold the entire product. (assuming that's what you want)
EDIT2:
If both operands are negative, just two's compliment both of them from the start and you won't have to worry about this.
Here's an example of multiplying by 3:
unsigned int y = (x << 1) + (x << 0);
(where I'm assuming that x is also unsigned).
Hopefully you should be able to generalise this.
As far as I know, there is no easy way to multiply in general using just 3 operators.
Multiplying with 60 is possible, since 60 = 64 - 4: (x << 6) - (x << 2)
17 = 16 + 1 = (2^4) + (2^0). Therefore, shift your number left 4 bits (to multiply by 2^4 = 16), and add the original number to it.
Another way to look at it is: 17 is 10001 in binary (base 2), so you need a shift operation for each of the bits set in the multiplier (i.e. bits 4 and 0, as above).
I don't know C, so I won't embarrass myself by offering code.
Numbers that would work with using only 3 operators (a shift, plus or minus, and another shift) is limited, but way more than the 3, 17 and 60 mentioned above. If a number can be represented as (2^x) +/- (2^y) it can be done with only 3 operators.

Resources