C 位除法舍入到最接近的零
我想执行有符号整数按2的幂进行位除。然而,我遇到了几个问题。我只是想知道是否有人能帮我 首先,我尝试单独使用位移位:C 位除法舍入到最接近的零,c,math,bit-manipulation,C,Math,Bit Manipulation,我想执行有符号整数按2的幂进行位除。然而,我遇到了几个问题。我只是想知道是否有人能帮我 首先,我尝试单独使用位移位: int result = number >> n; 然而,当我尝试除以一个负数时,我遇到了一个问题。(它总是用一个更大的数字取整。例如:-9/4=-3而不是-2。因此,我在互联网上查找这个问题,最终得到了以下解决方案: int result = (number + (1<<n)-1) >> n; int结果=(数字+(1 n; 但是,当我
int result = number >> n;
然而,当我尝试除以一个负数时,我遇到了一个问题。(它总是用一个更大的数字取整。例如:-9/4=-3而不是-2。因此,我在互联网上查找这个问题,最终得到了以下解决方案:
int result = (number + (1<<n)-1) >> n;
int结果=(数字+(1 n;
但是,当我尝试11/4=3而不是2时
有什么建议吗?我只能使用!~&^ |+>(没有循环或如果允许/开关)也许这会对您有所帮助 1) 如果您使用的是
/
运算符,则标准规定(ISO/IEC TR3 in 6.5.5乘法运算符中的/
)运算符的结果是第一个操作数除以第二个操作数的商
2) 如果您使用的>
标准规定(6.5.7中的ISO/IEC TR3
)是LHS操作数为有符号类型且为负数的
的结果,则结果值为实现定义的
因此,/
将为您提供所需的结果
但是有符号和负数上的
取决于编译器。以下方法不好,因为它依赖于:
- 负整数的右移是算术移位(可能不是这种情况)
- 符号整数是2的补码表示(极少数情况下可能不是这种情况)
- 没有任何填充位的整数(现在在现代CPU上你找不到填充位,尽管标准允许它们的存在)
由于有符号整数溢出,它可能会导致某些红利(例如,INT\u MIN
)出现未定义的行为
因此,它不可移植,也不能保证始终工作。您已收到警告
#include <stdio.h>
#include <limits.h>
int DivByShifting1(int n, unsigned shift)
{
int sgn = n >> ((sizeof(int) * CHAR_BIT) - 1);
return ((((n + sgn) ^ sgn) >> shift) + sgn) ^ sgn;
}
int main(void)
{
int n, s;
for (n = -10; n <= 10; n++)
for (s = 0; s <= 4; s++)
printf("%d / %d = %d\n", n, 1 << s, DivByShifting1(n, s));
return 0;
}
请注意,((sizeof(int)*CHAR_BIT)-1)
是编译时常量,因此可以允许*
和-
另一个版本非常类似,但不要求负整数的右移位为算术移位,并且不存在有符号整数溢出(2的补码和填充位仍然是限制,但实际上在今天的实践中存在):
@R.正确地提醒,从有符号整数
到无符号整数
的转换可以通过添加0u(无符号0)来完成
他还提醒说,可以直接返回un
,而不必执行memcpy()
到n
。转换应该由实现定义,但在C的2的补码实现中,比特对比特的复制实际上总是如此。只需使用//code>操作符:
int result = number / (1 << n);
intresult=number/(1从intdiv(inta){returna/4;}
的反汇编判断:
leal 3(%rdi), %eax
testl %edi, %edi
cmovns %edi, %eax
sarl $2, %eax
必须通过(1n)
调整操作数;这两种操作数都可以根据实现定义的行为使用无分支的bitmagic实现。我不清楚。1)您是使用/
获得结果,还是2)使用
执行等效除法?@Koushik,他说他只能使用这些操作符:!~&^ |+>。另外,没有循环或if条件/开关。@Koushik我正在调用一个函数div(11,2)来执行11/4@AnishRam我只是想确保他不会漏掉/
。现在我很清楚了。一个有用的链接,你能解释一下n>>((sizeof(int)*CHAR_位)-1)
在你的DivByShifting1
函数中做了什么吗?@AnishRam。它为n>=0提供了0,为n<0提供了-1。就我个人而言,我会使用实现定义的从无符号
到int
的转换(发生在返回
语句中)与其说memcpy
…不如说练习的重点是避免在源代码中进行显式除法。那么我认为这是不可移植的,因为>
是为负操作数定义的实现。您至少需要一种方法来根据操作数是否为负来调节表达式……或者它将使用idiv
;您可以将有符号整数强制转换为无符号整数,并使用最高有效位作为符号位值。我认为,它仍然是可行的,尽管要长得多。是的,刚刚添加了一个版本,不依赖于>
的实现定义行为。
-10 / 1 = -10
-10 / 2 = -5
-10 / 4 = -2
-10 / 8 = -1
-10 / 16 = 0
-9 / 1 = -9
-9 / 2 = -4
-9 / 4 = -2
-9 / 8 = -1
-9 / 16 = 0
-8 / 1 = -8
-8 / 2 = -4
-8 / 4 = -2
-8 / 8 = -1
-8 / 16 = 0
-7 / 1 = -7
-7 / 2 = -3
-7 / 4 = -1
-7 / 8 = 0
-7 / 16 = 0
-6 / 1 = -6
-6 / 2 = -3
-6 / 4 = -1
-6 / 8 = 0
-6 / 16 = 0
-5 / 1 = -5
-5 / 2 = -2
-5 / 4 = -1
-5 / 8 = 0
-5 / 16 = 0
-4 / 1 = -4
-4 / 2 = -2
-4 / 4 = -1
-4 / 8 = 0
-4 / 16 = 0
-3 / 1 = -3
-3 / 2 = -1
-3 / 4 = 0
-3 / 8 = 0
-3 / 16 = 0
-2 / 1 = -2
-2 / 2 = -1
-2 / 4 = 0
-2 / 8 = 0
-2 / 16 = 0
-1 / 1 = -1
-1 / 2 = 0
-1 / 4 = 0
-1 / 8 = 0
-1 / 16 = 0
0 / 1 = 0
0 / 2 = 0
0 / 4 = 0
0 / 8 = 0
0 / 16 = 0
1 / 1 = 1
1 / 2 = 0
1 / 4 = 0
1 / 8 = 0
1 / 16 = 0
2 / 1 = 2
2 / 2 = 1
2 / 4 = 0
2 / 8 = 0
2 / 16 = 0
3 / 1 = 3
3 / 2 = 1
3 / 4 = 0
3 / 8 = 0
3 / 16 = 0
4 / 1 = 4
4 / 2 = 2
4 / 4 = 1
4 / 8 = 0
4 / 16 = 0
5 / 1 = 5
5 / 2 = 2
5 / 4 = 1
5 / 8 = 0
5 / 16 = 0
6 / 1 = 6
6 / 2 = 3
6 / 4 = 1
6 / 8 = 0
6 / 16 = 0
7 / 1 = 7
7 / 2 = 3
7 / 4 = 1
7 / 8 = 0
7 / 16 = 0
8 / 1 = 8
8 / 2 = 4
8 / 4 = 2
8 / 8 = 1
8 / 16 = 0
9 / 1 = 9
9 / 2 = 4
9 / 4 = 2
9 / 8 = 1
9 / 16 = 0
10 / 1 = 10
10 / 2 = 5
10 / 4 = 2
10 / 8 = 1
10 / 16 = 0
int result = number / (1 << n);
leal 3(%rdi), %eax
testl %edi, %edi
cmovns %edi, %eax
sarl $2, %eax