你可以这样写:
int i = 3;
int k = 2;
int division = i / k;
int remainder = i % k;
似乎认为这会在低层次上要求 ALU 执行两种视觉操作:一种返回商,另一种返回余数。但是,我相信 ALU 很可能会在一次操作中计算两者。如果是这种情况,这不是最有效的。
有没有更有效的方法,而不要求 CPU 计算两次?换句话说,它可以在 C++ 的单个操作中完成吗?
你可以这样写:
int i = 3;
int k = 2;
int division = i / k;
int remainder = i % k;
似乎认为这会在低层次上要求 ALU 执行两种视觉操作:一种返回商,另一种返回余数。但是,我相信 ALU 很可能会在一次操作中计算两者。如果是这种情况,这不是最有效的。
有没有更有效的方法,而不要求 CPU 计算两次?换句话说,它可以在 C++ 的单个操作中完成吗?
实际上,您编写的代码不会生成任何除法指令,因为编译器可以在编译时计算出结果。我编写了一个小测试程序并设置编译器(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++ 编译器已经非常擅长这种优化。除非您有性能问题并且已经分析了您的代码以确定瓶颈在哪里,否则不要尝试再次猜测编译器。
当然:
int i = 3;
int k = 2;
int division = i / k;
int remainder = i - division * k;
另外,如果您真的想这样做,请查看div
,但我怀疑它会更快,就像我上面的解决方案一样。
ISO C99具有以下ldiv
功能:
#include <stdlib.h> ldiv_t ldiv(long numer, long denom); ldiv() 函数计算数值 numer/denom(分子/分母)。 它返回名为 ldiv_t 的结构中的商和余数,该结构包含 两个名为 quot 和 rem 的长成员。
是否在 FPU 级别减少到单个操作我不能说。
我不知道任何内置的东西,但你可以用乘法而不是除法来模拟它:
int division = i / k;
int remainder = i - (division * k);
当您问自己,什么是最快的时,通常最好对其进行基准测试(我喜欢这样做)。所以我从这里得到答案并编写了一个小型基准测试程序并将其扔到(我认为gcc
会得到类似的结果) (在他优化了所有东西并且我的基准测试被打破)。g++
-O0
-O1
我在笔记本电脑上执行了2^28
运行(从to运行)i
并获得了以下运行时:k
1
2^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.009 秒
ldiv_t d = ldiv(i,k);
division = d.quot;
remainder = d.rem;
18.845s
正如人们所看到的,这是有区别的,你最好的方法是乘法。该ldiv
方法也可以,但与其他方法相比,我发现它有点麻烦。