标准div()函数返回div_t结构作为参数,例如:
/* div example */
#include <stdio.h> /* printf */
#include <stdlib.h> /* div, div_t */
int main ()
{
div_t divresult;
divresult = div (38,5);
printf ("38 div 5 => %d, remainder %d.\n", divresult.quot, divresult.rem);
return 0;
}
我的情况有些不同。我有这个
#define NUM_ELTS 21433
int main ()
{
unsigned int quotients[NUM_ELTS];
unsigned int remainders[NUM_ELTS];
int i;
for(i=0;i<NUM_ELTS;i++) {
divide_single_instruction("ient[i],&reminder[i]);
}
}
我知道除法汇编语言可以在单个指令中完成所有操作,因此我需要在此处执行同样的操作以节省CPU周期,这是笨拙地将商从EAX移出,将提醒从EDX移至存储我的数组的存储位置。如何在我的C代码中不包含asm {}或SSE内部函数的情况下完成此操作?它必须是便携式的。
最佳答案
由于您是在原位写入数组(用商和余数替换分子和分母),因此在写入数组之前,应将结果存储到临时变量中。
void foo (unsigned *num, unsigned *den, int n) {
int i;
for(i=0;i<n;i++) {
unsigned q = num[i]/den[i], r = num[i]%den[i];
num[i] = q, den[i] = r;
}
}
产生这个主循环组件
.L5:
movl (%rdi,%rcx,4), %eax
xorl %edx, %edx
divl (%rsi,%rcx,4)
movl %eax, (%rdi,%rcx,4)
movl %edx, (%rsi,%rcx,4)
addq $1, %rcx
cmpl %ecx, %r8d
jg .L5
在一些更复杂的情况下,初次使用时会节省商和余数。例如,在通过试验划分测试素数时,您经常会看到这样的循环
for (p = 3; p <= n/p; p += 2)
if (!(n % p)) return 0;
事实证明GCC does not use the remainder from the first division并因此执行了两次除法指令,这是不必要的。为了解决这个问题,您可以在完成第一个除法时保存其余部分,如下所示:
for (p = 3, q=n/p, r=n%p; p <= q; p += 2, q = n/p, r=n%p)
if (!r) return 0;
这样可以将结果加快两倍。
因此,一般而言,GCC会做得很好,特别是如果您在第一次计算商和余数时保存了商和余数。