相关疑难解决方法(0)

为什么GCC在实现整数除法时使用乘以奇数的乘法?

我一直在阅读divmul组装操作,我决定通过在C中编写一个简单的程序来实现它们:

文件分割

#include <stdlib.h>
#include <stdio.h>

int main()
{
    size_t i = 9;
    size_t j = i / 5;
    printf("%zu\n",j);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后生成汇编语言代码:

gcc -S division.c -O0 -masm=intel
Run Code Online (Sandbox Code Playgroud)

但是看生成的division.s文件,它不包含任何div操作!相反,它通过位移和魔术数字来做某种黑魔法.这是一个计算代码片段i/5:

mov     rax, QWORD PTR [rbp-16]   ; Move i (=9) to RAX
movabs  rdx, -3689348814741910323 ; Move some magic number to RDX (?)
mul     rdx                       ; Multiply 9 by magic number
mov     rax, rdx                  ; Take only the upper 64 bits of the …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64 integer-division

206
推荐指数
4
解决办法
1万
查看次数

整数除以7

来源我的回答:

这个表达式在C预处理器中是否正确

我有点不在这里,我试图了解这种特殊优化是如何工作的.

正如答案中提到的,gcc将整数除法优化为7:

mov edx, -1840700269
mov eax, edi
imul    edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
Run Code Online (Sandbox Code Playgroud)

其转换为C为:

int32_t divideBySeven(int32_t num) {
    int32_t temp = ((int64_t)num * -015555555555) >> 32;
    temp = (temp + num) >> 2;
    return (temp - (num >> 31));
}
Run Code Online (Sandbox Code Playgroud)

我们来看看第一部分:

int32_t temp = ((int64_t)num * -015555555555) >> 32;
Run Code Online (Sandbox Code Playgroud)

为什么这个号码?

那么,让我们取2 ^ 64并将其除以7,看看弹出的是什么.

2^64 / 7 = 2635249153387078802.28571428571428571429
Run Code Online (Sandbox Code Playgroud)

这看起来像一团糟,如果我们把它转换成八进制怎么办?

0222222222222222222222.22222222222222222222222
Run Code Online (Sandbox Code Playgroud)

这是一个非常漂亮的重复模式,当然这不是巧合.我的意思是我们记得7是0b111,我们知道当我们除以99时,我们倾向于在基数10中得到重复模式.因此,当我们除以7时,我们在基数8中得到重复模式是有道理的.

那么我们的号码在哪里?

(int32_t)-1840700269 是相同的 (uint_32t)2454267027

* 7 …

algorithm math optimization integer-division compiler-optimization

13
推荐指数
1
解决办法
1554
查看次数