【发布时间】:2016-03-11 09:13:12
【问题描述】:
我试图从 www.spoj.com 解决这个练习:FCTRL - Factorial
你真的不必读它,如果你好奇就读吧:)
首先我用 C++ 实现它(这是我的解决方案):
#include <iostream>
using namespace std;
int main() {
unsigned int num_of_inputs;
unsigned int fact_num;
unsigned int num_of_trailing_zeros;
std::ios_base::sync_with_stdio(false); // turn off synchronization with the C library’s stdio buffers (from https://stackoverflow.com/a/22225421/5218277)
cin >> num_of_inputs;
while (num_of_inputs--)
{
cin >> fact_num;
num_of_trailing_zeros = 0;
for (unsigned int fives = 5; fives <= fact_num; fives *= 5)
num_of_trailing_zeros += fact_num/fives;
cout << num_of_trailing_zeros << "\n";
}
return 0;
}
我把它作为 g++ 5.1
的解决方案上传了但后来我看到一些 cmets 声称他们的时间执行小于 0.1。由于我想不出更快的算法,我尝试在 C 中实现相同的代码:
#include <stdio.h>
int main() {
unsigned int num_of_inputs;
unsigned int fact_num;
unsigned int num_of_trailing_zeros;
scanf("%d", &num_of_inputs);
while (num_of_inputs--)
{
scanf("%d", &fact_num);
num_of_trailing_zeros = 0;
for (unsigned int fives = 5; fives <= fact_num; fives *= 5)
num_of_trailing_zeros += fact_num/fives;
printf("%d", num_of_trailing_zeros);
printf("%s","\n");
}
return 0;
}
我把它作为 gcc 5.1
的解决方案上传了现在代码几乎相同,我按照here 的建议将std::ios_base::sync_with_stdio(false); 添加到C++ 代码中以关闭与C 库的stdio 缓冲区的同步。我还将printf("%d\n", num_of_trailing_zeros); 拆分为printf("%d", num_of_trailing_zeros); printf("%s","\n");,以补偿cout << num_of_trailing_zeros << "\n"; 中operator<< 的双重调用。
但我仍然看到 C 与 C++ 代码相比 x9 更好的性能和更低的内存使用率。
这是为什么呢?
编辑
我在 C 代码中将 unsigned long 固定为 unsigned int。应该是unsigned int,上面显示的结果与新的(unsigned int)版本有关。
【问题讨论】:
-
C++ streams are extremely slow by design. 因为缓慢而稳定地赢得比赛。 :P(在我被激怒之前运行)
-
缓慢并非来自安全性或适应性。它的所有流标志都被过度设计了。
-
@AlexLop。使用
std::ostringstream来累积输出并将其发送到std::cout最后一次性 将时间降低到0.02。在循环中使用std::cout在他们的环境中只是速度较慢,我认为没有简单的方法可以改进它。 -
没有其他人担心这些时间是使用 ideone 获得的吗?
-
@Olaf:恐怕我不同意,这种问题对于所有选择的标签来说都是非常重要的。 C 和 C++ 通常足够接近,以至于性能上的这种差异需要一个解释。我很高兴我们找到了。或许 GNU libc++ 应该因此得到改进。
标签: c++ c performance gcc iostream