我正在尝试通过使用泰勒级数、牛顿法、连分数等来击败 C++ 的
pow
函数,目标是比 pow
更快地获得良好的近似值。
我写了一些函数来与
pow
进行基准测试,我尝试使用std::chrono::steady_clock
来测量执行时间。我的想法是运行该函数 1048576 次并将持续时间除以 1048576 以获得单次通过时间:
#include <chrono>
#include <cmath>
#include <iostream>
#include <string>
using std::chrono::steady_clock;
using std::chrono::duration;
using std::cout;
float newton(float base, int exp, int lim) {
float i = 1.0 / exp;
float r = 1 + (base - 1) / exp;
exp--;
for (int c = 0; c < lim; c++) {
r = i * (exp * r + base / pow(r, exp));
}
return r;
}
int main()
{
auto start = steady_clock::now();
float r;
for (int64_t i = 0; i < 1048576; i++) {
r = newton(256.0, 3, 16);
}
auto end = steady_clock::now();
duration<double, std::nano> time = end - start;
cout << "newton(256, 3, 16): " << time.count() / 1048576 << " nanoseconds\n";
}
但是得到的测量值根本没有意义:
PS C:\Users\Xeni> C:\Users\Xeni\source\repos\exponentiation\x64\Release\exponentiation.exe
newton(256, 3, 16): 0 nanoseconds
PS C:\Users\Xeni> C:\Users\Xeni\source\repos\exponentiation\x64\Release\exponentiation.exe
newton(256, 3, 16): 9.53674e-05 nanoseconds
PS C:\Users\Xeni> C:\Users\Xeni\source\repos\exponentiation\x64\Release\exponentiation.exe
newton(256, 3, 16): 9.53674e-05 nanoseconds
PS C:\Users\Xeni> C:\Users\Xeni\source\repos\exponentiation\x64\Release\exponentiation.exe
newton(256, 3, 16): 9.53674e-05 nanoseconds
我的CPU运行在3GHz,即每秒30亿个时钟周期,因此一个时钟周期约为3.33333333333333E-10秒,如果结果可信,那么计算发生在大约1e-4纳秒内,即1e -13秒,不到一个时钟周期。
我使用 Visual Studio 2022 编译,编译器参数:
/permissive- /ifcOutput "x64\Release\" /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Ob1 /sdl /Fd"x64\Release\vc143.pdb" /Zc:inline /fp:fast /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /std:c17 /Gd /Oi /MD /std:c++20 /FC /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Ot /Fp"x64\Release\exponentiation.pch" /diagnostics:column
我在 PowerShell 中测量了整个程序的执行情况,计算出单次运行大约需要 8 纳秒(如果 PowerShell 正确的话):
PS C:\Users\Xeni> measure-command {C:\Users\Xeni\source\repos\exponentiation\x64\Release\exponentiation.exe}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 8
Ticks : 89682
TotalDays : 1.03798611111111E-07
TotalHours : 2.49116666666667E-06
TotalMinutes : 0.00014947
TotalSeconds : 0.0089682
TotalMilliseconds : 8.9682
PS C:\Users\Xeni> 8.9682/1048576*1e6
8.55274200439453
我的代码有什么问题?我该如何解决它?
正如我在评论中提到的。编译器看到
newton
函数并没有真正改变程序状态,并且返回值被忽略。并且每次的参数都相同。
一些快速且简单的随机性和累积
r
返回值是任何简单的解决方案。
int main()
{
auto start = steady_clock::now();
float r = 0;
for (int64_t i = 0; i < 1048576; i++) {
r += newton(256.0+rand()%40, 3, 16);
}
auto end = steady_clock::now();
duration<double, std::nano> time = end - start;
cout << "newton(256, 3, 16): " << time.count() / 1048576 << " nanoseconds\n";
cout << "r for the sake of r: " << r << std::endl;
}