Reputation: 67
I need to compute a number (a/(2**b) using only bitwise operators such as ! & ^ ~ and shifts. I was given the following hint but I'm new to C and I dont know what the code means:
int bias = x>0 ? 0 : ((1<<n)-1);
Can anyone explain it to me?
I thought a>>b would work but I dont think it works for negative numbers.
Upvotes: 0
Views: 6808
Reputation: 1
As answered already, the ? :
operators are the 'ternary operator'. To the left of the ?
is a condition. If the condition is true, the block returns what's between the ?
and :
, and if false, returns what's to the right of :
.
In the context of signed division by 2 rounding towards zero. If the numerator is positive, then a logical right-shift gives the correct result. For negative (two's complement) integers it takes a bit more work. The first step is to replace the logical shift with an aritmetic one. For exact multiples of 2, the correct answer is still given, but other values are rounded towards minus infinity. Here, adding the "bias" corrects this.
Therefore, for positive integers, no bias is required, but for negative integers, a bias of 2b - 1 has to be added to the numerator. The full code is hence something like the following:
int div2(int x, int b)
{
int bias = x>0 ? 0 : ((1<<b)-1);
return (x+bias)>>b; // Note this only works if >> is an arithmetic shift.
}
Note that some care has to be taken if b is equal to or greater than 32, as (1<<b)
may not produce what you expect (same goes with the below example).
In x86 assembly language, you might want something like the following (I hope my assembly knowledge is still good!):
; Assume the numerator is in ECX and the value of b is in EDX for this example
; Prologue to preserve some extra registers
PUSH EBX
PUSH ESI
; Register rearrangement (only CL is valid for variable shifts)
MOV EAX, ECX
MOV CL, DL
; Prepare bias mask
MOV ESI, 1
SHL ESI, CL
SUB ESI, 1
; Apply bias if numerator is negative
XOR EBX, EBX
TEST EAX, EAX
CMOVS EBX, ESI ; Sets EBX to ESI if the sign bit is set by TEST, otherwise EBX is left as is (equal to 0)
; Perform arithmetic shift with bias
ADD EAX, EBX
SAR EAX, CL
; Epilogue
POP ESI
POP EBX
; Result in EAX
RET
This is a homework-like question, but it is also useful in the field of compiler development.
Please note that this isn't the fastest algorithm around. In assembly, it would be something like this:
; Assume the numerator is in ECX and the value of b is in EDX for this example
PUSH EBX
MOV EAX, ECX
MOV EBX, ECX
MOV ECX, EDX
MOV EDX, 1
SHL EDX, CL
SUB EDX, 1
SAR EAX, 31
AND EAX, EDX
ADD EAX, EBX
SAR EAX, CL
POP EBX
RET
Upvotes: 0
Reputation: 882
Sigh... this is a homework question. The student is asking for help with an assignment from the Computer Systems, a Programmers' Perspective textbook.
For future reference, any time someone says "I'm only allowed to use the XYZ operators to do something", it's probably a homework question.
I don't suppose there's a way to take reputation away from people who ask for help with homework questions, is there?
Upvotes: -1
Reputation: 1
well,x<<n
works correctly for positive numbers. so why dont you just use something like
result=if sign=1 then (x<<n) else(-x<<n)
(replace the iftehenelse by some masking with the sign bit)
Upvotes: 0
Reputation: 17016
That particular bit of code gives you a bias of 0 if x is positive. Otherwise it produces a mask of the lower n bits. The x = a ? b : c;
pattern is called the ternary operator(technically the 'conditional operator', apparently) in C.
n (1<<n) (1<<n)-1 binary
0 0x01 0x00 00000000
1 0x02 0x01 00000001
2 0x04 0x03 00000011
3 0x08 0x07 00000111
4 0x10 0x0F 00001111
5 0x20 0x1F 00011111
6 0x40 0x3F 00111111
7 0x80 0x7F 01111111
...
Upvotes: 3