最近,我了解到mod('%')运算符非常缓慢。因此,我创造了一个函数,它将像a%b一样工作。但它是否比mod运算符更快呢?
这是我的函数
int mod(int a, int b)
{
int tmp = a/b;
return a - (b*tmp);
}
最近,我了解到mod('%')运算符非常缓慢。因此,我创造了一个函数,它将像a%b一样工作。但它是否比mod运算符更快呢?
这是我的函数
int mod(int a, int b)
{
int tmp = a/b;
return a - (b*tmp);
}
int fast_mod(const int input, const int ceil) {
// apply the modulo operator only when needed
// (i.e. when the input is greater than the ceiling)
return input >= ceil ? input % ceil : input;
// NB: the assumption here is that the numbers are positive
}
我建议您观看整个演讲,他会更详细地解释为什么这种方法比仅无条件使用%
更快。
fast_mod
对于负数输入似乎有问题:-5%5 == 0
,但是fast_mod(-5,5)== -5
。 - Nikolai Ruhe这可能会受到编译器和平台的影响。
但是我对此很感兴趣,在我的系统上,根据我的基准测试,您似乎是正确的。但是@865719的答案中的方法最快:
#include <chrono>
#include <iostream>
class Timer
{
using clk = std::chrono::steady_clock;
using microseconds = std::chrono::microseconds;
clk::time_point tsb;
clk::time_point tse;
public:
void clear() { tsb = tse = clk::now(); }
void start() { tsb = clk::now(); }
void stop() { tse = clk::now(); }
friend std::ostream& operator<<(std::ostream& o, const Timer& timer)
{
return o << timer.secs();
}
// return time difference in seconds
double secs() const
{
if(tse <= tsb)
return 0.0;
auto d = std::chrono::duration_cast<microseconds>(tse - tsb);
return d.count() / 1000000.0;
}
};
int mod(int a, int b)
{
int tmp=a/b;
return a-(b*tmp);
}
int fast_mod(const int input, const int ceil) {
// apply the modulo operator only when needed
// (i.e. when the input is greater than the ceiling)
return input < ceil ? input : input % ceil;
// NB: the assumption here is that the numbers are positive
}
int main()
{
auto N = 1000000000U;
unsigned sum = 0;
Timer timer;
for(auto times = 0U; times < 3; ++times)
{
std::cout << " run: " << (times + 1) << '\n';
sum = 0;
timer.start();
for(decltype(N) n = 0; n < N; ++n)
sum += n % (N - n);
timer.stop();
std::cout << " %: " << sum << " " << timer << "s" << '\n';
sum = 0;
timer.start();
for(decltype(N) n = 0; n < N; ++n)
sum += mod(n, N - n);
timer.stop();
std::cout << " mod: " << sum << " " << timer << "s" << '\n';
sum = 0;
timer.start();
for(decltype(N) n = 0; n < N; ++n)
sum += fast_mod(n, N - n);
timer.stop();
std::cout << "fast_mod: " << sum << " " << timer << "s" << '\n';
}
}
构建: GCC 5.1.1
(x86_64)
g++ -std=c++14 -march=native -O3 -g0 ...
输出:
run: 1
%: 3081207628 5.49396s
mod: 3081207628 4.30814s
fast_mod: 3081207628 2.51296s
run: 2
%: 3081207628 5.5522s
mod: 3081207628 4.25427s
fast_mod: 3081207628 2.52364s
run: 3
%: 3081207628 5.4947s
mod: 3081207628 4.29646s
fast_mod: 3081207628 2.56916s
C++11
来编译代码。在我的测试中,你的新函数与fast_mod
差不多。 - Galik在某些情况下,程序员可以通过知道操作数的信息,超越编译器在余数运算中的表现。例如,如果基数可能是2的幂次方,但不太可能比要减小的值大,那么可以使用类似以下的方法:
unsigned mod(unsigned int x, unsigned int y)
{
return y & (y-1) ? x % y : x & (y-1);
}
unsigned
?我和编译器以前从未见过。 - Akib Azmain Turja我想在这个讨论中为大家贡献一点。如果你想处理负数,可以使用以下函数:
inline long long mod(const long long x, const long long y) {
if (x >= y) {
return x % y;
} else if (x < 0) {
return (x % y + y) % y;
} else {
return x;
}
}
大多数情况下,您的微优化代码不会比编译器更快。我也不知道那些声称内置%
很慢的“智慧”来自哪里。它的速度与机器能够计算的速度一样快 - 借助编译器为您执行的所有微优化。
还要注意,对于这种非常小的代码片段的性能测量并不是一项容易的任务。循环结构的条件语句或时间测量的抖动可能会影响您的结果。您可以在像Andrei Alexantrescu或Chandler Caruth这样的人在YouTube上找到有关此类问题的讲座。我曾经为我正在工作的项目编写过一个微基准测试框架。确实有很多需要关注的事情,包括外部因素,例如操作系统抢占您的线程或将其移动到另一个核心。