C – Multiplying Fractions with Bitwise Operations

bit-manipulationcfractions

Okay so I've been stuck trying to find out how to multiply the fraction (3/4) by a signed integer in c. The challenge is using only the logical operators (! ~ & ^ | + << >>) with no (if statements, loops, etc.) and using a max of 12 logical operators. The goal is mimic the following expression (x*3/4) EXACTLY. Now I have taken a look at other questions with similar problem (just with different fraction) however the solutions to those have over 12 operators used. I've tried simplifying them but just can't seem to do it without having the solution not working. Here's the solution from the 5/8 question:

int s = -((num >> 31) & 1); // sign bit as -1 or 0

int n = (num ^ s) - s; // twos complement if negative

int x = n >> 3; // divide by 8

x = (x << 2) + x;   // multiply by 5; no overflow yet since 5/8 is less than one

int y = n & 7;  // the bits we shifted out

y = (y << 2) + y;   // multiply by 5; no overflow

return (s ^ (x + (y >> 3))) - s; // the two pieces and complemented back

I'm not sure if the above method is correct since I plugged in -2 and did it out by hand and got -3 back. Should've been -1 since -2 * (5/8) = -1.25

My original thought to solve this was to check for and overflow. This is because a simple program like:

x = (x<<1) + x;
x = X>>2;

in an overflow case would cause the answer to be off by +1. To solve the problem I thought I would have to divide the limits by 3 and check and see if the integer being multiplied is greater than 715827882 or -715827882. If the number is greater, get a 1 from the comparison and add it to the final result or if it less than then get a 0 and add 0 to the final result. I feel like this way is hard to implement with no if statements and that it might use more than 12 operators. I'm just asking for help on what could be the best way to approach the problem. Thanks in advance!

Best Answer

What you thought about was:

x=(x<<1)+x; // do x=x*3 x=x>>2; // do x=x/4

This can overflow since x hold a larger value first. Would this work?

x=x-(x>>2); // do x=x-x/4, equal to 3/4

Of course, because x>>2 throws away the lowest bit, so the result is truncated up. If you need truncation down, this is wrong and you should use addition:

x=(x>>1)+((x+1)>>2); // x=x/2+x/4

EDIT: you need (x+1)>>2 to avoid double truncation result lost, such as x=7.