c - 分数与位运算相乘
c - Multiplying Fractions with Bitwise Operations
好吧,我一直在试图找出如何在 c 中将分数 (3/4) 乘以有符号整数。挑战在于仅使用逻辑运算符 (! ~ & ^ | + << >>),不使用(if 语句、循环等)并且最多使用 12 个逻辑运算符。目标是准确模拟以下表达式 (x*3/4)。现在我已经查看了具有类似问题(只是分数不同)的其他问题,但是这些问题的解决方案使用了超过 12 个运算符。我试过简化它们,但如果解决方案不起作用,我似乎无法做到这一点。这是 5/8 问题的答案:
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
我不确定上面的方法是否正确,因为我插入了-2 并手动完成并得到了-3。应该是 -1 因为 -2 * (5/8) = -1.25
我最初解决这个问题的想法是检查溢出。这是因为一个简单的程序,如:
x = (x<<1) + x;
x = X>>2;
在溢出的情况下会导致答案偏离 +1。为了解决这个问题,我想我必须将限制除以 3,然后检查乘以的整数是否大于 715827882 或 -715827882。如果数字更大,则从比较中获得 1 并将其添加到最终结果中,或者如果数字小于则获得 0 并将 0 添加到最终结果中。我觉得这种方式很难在没有 if 语句的情况下实现,并且它可能使用超过 12 个运算符。我只是在寻求解决问题的最佳方法的帮助。提前致谢!
您想到的是:
x=(x<<1)+x; // do x=x*3
x=x>>2; // do x=x/4
这可能会溢出,因为 x
首先保存一个较大的值。这行得通吗?
x=x-(x>>2); // do x=x-x/4, equal to 3/4
当然,因为x>>2
丢掉了最低位,所以结果被截断了。如果你需要向下截断,这是错误的,你应该使用加法:
x=(x>>1)+((x+1)>>2); // x=x/2+x/4
编辑:您需要 (x+1)>>2
以避免双截断结果丢失,例如 x=7。
好吧,我一直在试图找出如何在 c 中将分数 (3/4) 乘以有符号整数。挑战在于仅使用逻辑运算符 (! ~ & ^ | + << >>),不使用(if 语句、循环等)并且最多使用 12 个逻辑运算符。目标是准确模拟以下表达式 (x*3/4)。现在我已经查看了具有类似问题(只是分数不同)的其他问题,但是这些问题的解决方案使用了超过 12 个运算符。我试过简化它们,但如果解决方案不起作用,我似乎无法做到这一点。这是 5/8 问题的答案:
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
我不确定上面的方法是否正确,因为我插入了-2 并手动完成并得到了-3。应该是 -1 因为 -2 * (5/8) = -1.25
我最初解决这个问题的想法是检查溢出。这是因为一个简单的程序,如:
x = (x<<1) + x;
x = X>>2;
在溢出的情况下会导致答案偏离 +1。为了解决这个问题,我想我必须将限制除以 3,然后检查乘以的整数是否大于 715827882 或 -715827882。如果数字更大,则从比较中获得 1 并将其添加到最终结果中,或者如果数字小于则获得 0 并将 0 添加到最终结果中。我觉得这种方式很难在没有 if 语句的情况下实现,并且它可能使用超过 12 个运算符。我只是在寻求解决问题的最佳方法的帮助。提前致谢!
您想到的是:
x=(x<<1)+x; // do x=x*3
x=x>>2; // do x=x/4
这可能会溢出,因为 x
首先保存一个较大的值。这行得通吗?
x=x-(x>>2); // do x=x-x/4, equal to 3/4
当然,因为x>>2
丢掉了最低位,所以结果被截断了。如果你需要向下截断,这是错误的,你应该使用加法:
x=(x>>1)+((x+1)>>2); // x=x/2+x/4
编辑:您需要 (x+1)>>2
以避免双截断结果丢失,例如 x=7。