我们需要通过在C/C++中实现特定算法来解决的大多数科学计算问题要求精度远低于双精度.例如1e-6
,1e-7
精度覆盖99%
的情况下,对ODE求解或数值积分.即使在我们确实需要更高精度的极少数情况下,通常数值方法本身也会在我们梦想达到接近双精度的精度之前失败.示例:即使在求解标准nostiff常微分方程时,由于舍入误差,我们也不能期望简单Runge-Kutta方法的1e-16精度.在这种情况下,双精度要求类似于要求更好地逼近错误答案.
然后,在大多数情况下,积极的浮点优化似乎是一个双赢的局面,因为它使您的代码更快(更快!)并且它不会影响您的特定问题的目标准确性.也就是说,确保特定的实现/代码对fp优化是稳定的似乎非常困难.古典(有点令人不安)的例子:GNL,GNU科学图书馆,不仅是市场上的标准数字图书馆,而且它是一个写得很好的图书馆(我无法想象自己做得更好).但是,GSL对fp优化不稳定.实际上,例如,如果使用intel编译器编译GSL,那么除非-fp-model strict
打开关闭fp优化的标志,否则其内部测试将失败.
因此,我的问题是:是否存在编写代码的一般准则,这些代码对于积极的浮点优化是稳定的.这些指南语言(编译器)是否具体.如果是这样,那么C/C++(gcc/icc)的最佳实践是什么?
注1:这个问题不是询问gcc/icc中的fp优化标志是什么.
注2:这个问题不是询问有关C/C++优化的一般指导原则(比如不要将虚函数用于大量调用的小函数).
注3:这个问题不是要求大多数标准fp优化列表(如x/x - > 1).
注4:我坚信这不是类似于传统的"最酷的服务器名称"的主观/偏离主题的问题.如果您不同意(因为我没有提供具体的示例/代码/问题),请将其标记为社区维基.我对答案比对获得一些状态点更感兴趣(不是它们不重要 - 你明白了!).
在此std :: function vs template链接中,对std :: function的开销进行了很好的讨论。基本上,为避免传递给std :: function构造函数的函子的堆分配导致10倍的开销,必须使用std :: ref或std :: cref。
来自@CassioNeri答案的示例显示了如何通过引用将lambdas传递给std :: function。
float foo(std::function<float(float)> f) { return -1.0f * f(3.3f) + 666.0f; }
foo(std::cref([a,b,c](float arg){ return arg * 0.5f; }));
Run Code Online (Sandbox Code Playgroud)
现在,英特尔线程构建模块库使您能够使用lambda / functor并行评估循环,如下例所示。
示例代码:
#include "tbb/task_scheduler_init.h"
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include "tbb/tbb_thread.h"
#include <vector>
int main() {
tbb::task_scheduler_init init(tbb::tbb_thread::hardware_concurrency());
std::vector<double> a(1000);
std::vector<double> c(1000);
std::vector<double> b(1000);
std::fill(b.begin(), b.end(), 1);
std::fill(c.begin(), c.end(), 1);
auto f = [&](const tbb::blocked_range<size_t>& r) {
for(size_t j=r.begin(); j!=r.end(); ++j) …
Run Code Online (Sandbox Code Playgroud) 我已经有一段时间没有在 StackOverflow 上发布任何问题了;我希望我或多或少记住了解决问题的适当方式(提前抱歉)。
\n我正在使用 C++ 流和 FMT 库,它提供了 C++23 打印的预览。当设置填充符来完成整数的显示宽度时,流很冷。例子:
\nconst int y = 730;\ncout << "y = " << setw(5) << y << endl;\ncout << "y = " << setfill('0') << setw(5) << y << endl;\ncout << "y = " << setfill('X') << setw(5) << y << endl;\ncout << "y = " << setfill('*') << setw(5) << y << endl;\n
Run Code Online (Sandbox Code Playgroud)\n输出是
\ny = 730\ny = 00730\ny = XX730\ny = **730\n
Run Code Online (Sandbox Code Playgroud)\n我试图使用 fmt::print\xe2\x80\x94 设置相同的填充符(包括“X”和“*”字符),例如:
\n …