我有一组方程,它们采用向量输入并返回不同时间步长的解。方程中有一些参数是在运行时接收的,并在该周期内保持不变。我想用运行时计算的值替换此类参数,以便进一步计算使用带有参数替换值的方程。原始问题有 4000 个这样的参数,但我给出了一个示例方程来说明我想要实现的目标。 一个较小的例子来说明这个问题:
rval[0] = -p1*x + p2*y*z;
rval[1] = -rval[0] - p3*y*y - dy;
rval[0] -= dx;
rval[2] = x + y + z - 1;
{p1,p2,p3} 是一组固定参数,其值是在线接收的,新的方程组本质上将变为
rval[0] = (-0.04)*x + (1.0e4)*y*z;
rval[1] = -rval[0] - (3.0e7)*y*y - dy;
rval[0] -= dx;
rval[2] = x + y + z - 1;
我尝试过的一种方法是使用 symengine 符号 C++ 库,但它增加了使用 symengine 方程的替换和计算的开销 使用 symengine 库尝试了上述方程的代码
// Create a map for substitution
SymEngine::map_basic_basic subs_map;
subs_map[x_sym] = real_double(x);
subs_map[y_sym] = real_double(y);
subs_map[z_sym] = real_double(z);
subs_map[dx_sym] = real_double(dx);
subs_map[dy_sym] = real_double(dy);
subs_map[dz_sym] = real_double(dz);
// Evaluate equations
rval[0] = SymEngine::eval_double(*resv1->subs(subs_map));
rval[1] = SymEngine::eval_double(*resv2->subs(subs_map));
rval[2] = SymEngine::eval_double(*resv3->subs(subs_map));
方程 resv1、resv2 和 resv3 与上述方程相同,但参数被替换 是否有其他方法可以通过替换参数来实现高速评估方程,或者是否有更快的方法在 symengine 中实现此目的。 注意:请注意,我使用的方程组比这个大得多,每个时间步运行多次迭代,但我正在尝试使用较小的方程组来检查解决方案的可行性。
使用
double p2 = 1.0e4
或常数 1.0e4
对于浮点数学单元来说确实没有多大关系。 如果您使用 -ffast-math
,它可能会产生一些影响,因为它可以让编译器重新排序浮点表达式,使其不完全匹配 IEEE 所需的结果,而是生成代数等效的方程。
请参阅 gcc 的 ffast-math 实际上是做什么的?,了解
-ffast-math
的作用和替代方案的详细信息。
即使使用
ffast-math
,真正的常量(即,使用硬编码的常量重新编译程序)可能会在某些情况下导致重大重写(即,它解决了你的常量意味着某个值乘以0,因此它跳过计算值),但如果没有这个值,你就不会得到太大的改进。 如果要求人类连续几百万次乘以 3 乘以 10 到 7,人类可能会变得更快,但 FPU 不会。 百万分之一的乘法也会同样快。
您可以安排数学运算以使 FPU 更快,但这主要涉及使您的数学遵循 SIMD 模式,每个周期执行 4 或 8 或更多并行浮点运算;或者在更极端的情况下,安排您的代码在 GPU 上运行(它可以像超宽 SIMD FPU 一样工作,非常便宜地并行执行 100 个相同的操作)。
这些看起来都不像“修复一些参数”后会神奇地发生的事情。 他们需要您的工作才能开始工作。