【发布时间】:2021-06-03 15:13:56
【问题描述】:
在我的代码中,我在一个循环中多次对 double 进行符号检查,并且该循环通常在执行期间运行数百万次。
我的符号检查是使用fabs() 进行的非常基本的计算,所以我认为必须有其他可能更快的方法,因为“除法很慢”。我遇到了一个模板函数和copysign(),并创建了一个简单的程序来运行速度比较。我已经用下面的代码测试了三种可能的解决方案。
// C++ program to find out execution time of of functions
#include <chrono>
#include <iostream>
#include <math.h>
using namespace std;
using namespace std::chrono;
template<typename Clock>
void printResult(const std::string name, std::chrono::time_point<Clock> start, std::chrono::time_point<Clock> stop, const int iterations)
{
// Get duration.
std::chrono::duration my_duration = duration_cast<nanoseconds>(stop - start);
my_duration /= iterations;
cout << "Time taken by "<< name <<" function: " << my_duration.count() << " ns avg. for " << iterations << " iterations." << endl << endl;
}
template <typename T> int sgn(T val)
{
return (T(0) < val) - (val < T(0));
}
int main() {
// ***************************************************************** //
int numiters = 100000000;
double vel = -0.6574;
double result = 0;
// Get starting timepoint
auto start_1 = high_resolution_clock::now();
for(int x = 0; x < numiters; x++)
{
result = (vel/fabs(vel)) * 12.1;
}
// Get ending timepoint
auto stop_1 = high_resolution_clock::now();
cout << "Result is: " << result << endl;
printResult("fabs", start_1, stop_1, numiters);
// Get starting timepoint
result = 0;
auto start_2 = high_resolution_clock::now();
for(int x = 0; x < numiters; x++)
{
result = sgn(vel) * 12.1;
}
// Get ending timepoint
auto stop_2 = high_resolution_clock::now();
cout << "Result is: " << result << endl;
printResult("sgn", start_2, stop_2, numiters);
// Get starting timepoint
result = 0;
auto start_10 = high_resolution_clock::now();
for(int x = 0; x < numiters; x++)
{
result = copysign(12.1, vel);
}
// Get ending timepoint
auto stop_10 = high_resolution_clock::now();
cout << "Result is: " << result << endl;
printResult("copysign", start_10, stop_10, numiters);
cout << endl;
}
当我运行程序时,我有点惊讶地发现fabs() 解决方案和copysign 解决方案在执行时间上几乎相同。此外,当我多次运行时,我发现结果可能会变化很大。
我的时间正确吗?还有比我测试过的三个例子更好的方法吗?
更新
我已经在quick-bench.com 上实现了测试,其中可以指定编译器设置,并且所有 3 个结果似乎在那里几乎相同。我想我可能有问题: https://quick-bench.com/q/PJiAmoC2NQIJyuvbdz5ZHUALu2M
【问题讨论】:
-
有一个std::signbit。在IEEE 754(通常用于
float和double)中,浮点的符号是一个额外的位。因此,我希望它会非常快。 -
你确定编译器没有完全忽略你的循环吗?除非有一些与浮点相关的怪异之处,否则我不会在程序集中的 main 中看到单个循环。
-
根据Compiler Explorer,它似乎实际上浓缩为一个简单的位检查(如果我正确解释了ASM)。
-
您使用什么编译器标志?您可以使用 quick-bench.com 将其重写为微基准测试的任何机会
-
编写性能测试并不是那么简单。很容易犯无形的错误,从而导致错误的结果。构建标志很重要,代码也必须仔细编写,这样编译器才不会删除测试代码(ASIF 规则提供了这种可能性)。请注意上面的评论和提供的在线工具链接。
标签: c++ benchmarking timing