是否有一个c ++函数(内置或其他)给出整数除法和模块除法结果而不重复操作?

时间:2011-09-14 22:46:54

标签: c++ integer-division

你可以这样写:

int i = 3;
int k = 2;
int division = i / k;
int remainder = i % k;

似乎认为这会在低级别上要求ALU执行两个视觉操作:一个返回商,一个返回剩余部分。但是,我相信ALU最有可能在一次操作中计算两者。如果是这种情况,那就不是最佳效率了。

是否有更有效的方法,而不要求CPU计算两次?换句话说,它可以在C ++的单个操作中完成吗?

5 个答案:

答案 0 :(得分:9)

实际上,您编写的代码不会生成任何除法指令,因为编译器可以在编译时计算出结果。我编写了一个小测试程序并设置编译器(VC ++ 10SP1)以生成汇编代码列表。

#include <iostream>

using namespace std;

struct result {
    long quotient, remainder;
};

result divide(long num, long den) {
    result d = { num / den, num % den };
    return d;
}

int main() {
    result d = divide(3, 2);
    d = divide(10, 3);
    cout << d.quotient << " : " << d.remainder << endl;
    return 0;
}

我必须以这种方式编写它并明确告诉编译器不要内联任何函数。 否则编译器会愉快地优化大部分代码。以下是除法函数的结果汇编代码。

; 8    : result divide(long num, long den) {

  00000 55       push    ebp
  00001 8b ec        mov     ebp, esp

; 9    :     result d = { num / den, num % den };

  00003 99       cdq
  00004 f7 7d 08     idiv    DWORD PTR _den$[ebp]

; 10   :     return d;
; 11   : }

  00007 5d       pop     ebp
  00008 c3       ret     0

生成单个IDIV指令并使用由它生成的商和余数足够聪明。现代C和C ++编译器在这种优化方面已经非常擅长。除非您遇到性能问题并且已经分析了代码以确定瓶颈所在,否则不要试图再次猜测编译器。

答案 1 :(得分:5)

不确定

int i = 3;
int k = 2;
int division = i / k;
int remainder = i - division * k;

另外,如果你真的想这样做,请看div,我怀疑它更快,就像我上面的解决方案一样。

答案 2 :(得分:5)

ISO C99具有ldiv功能:

#include <stdlib.h>

ldiv_t ldiv(long numer, long denom);

The ldiv() function computes the value numer/denom (numerator/denominator).
It returns the quotient and remainder in a structure named ldiv_t that contains
two long members named quot and rem.

是否在FPU级别减少到单个操作我不能说。

答案 3 :(得分:1)

我不知道内置任何内容,但你可以用乘法而不是除法来模拟它:

int division = i / k;
int remainder = i - (division * k);

答案 4 :(得分:0)

当你问自己,什么是最快的时候,通常一个好主意来对它进行基准测试(我喜欢这样做)。所以我从这里得到了答案并编写了一个很小的基准测试程序并将其投放到gcc(我认为g++的预期类似结果)-O0-O1他优化了一切,我的基准被破坏了。

我在笔记本电脑上执行了2^28次运行(ik12^14)并获得了以下运行时间:

division = 0;
remainder = 0;
// this test is only there to measure the constant overhead!

1.676s

division = i/k;
remainder = i%k;

24.614s

division = i/k;
remainder = i - division*k;

15.009s

ldiv_t d = ldiv(i,k);
division = d.quot;
remainder = d.rem;

18.845s

正如人们所看到的,的差异,你最好的镜头是乘法方法。 ldiv方法也没问题,但我发现它与其他方法相比有点麻烦。