处理科学代码中许多常量、变量的 C++ 最佳实践

计算科学 C++
2021-11-27 21:53:01

我正在开发一个代码来模拟流体流动中存在的生物物质。这涉及与一些额外的生物模型耦合的标准 Navier-Stokes 方程。有许多参数/常数。

我已经编写了处理主要计算的函数,但我遇到的一个问题是这些计算所依赖的大量常量/参数。将 10-20 个参数传递给函数似乎很麻烦。

一种替代方法是使所有常量成为全局变量,但我知道这在 C++ 中是不受欢迎的。

处理函数的许多输入的标准方法是什么?我应该制作一个结构并传递它吗?

谢谢

3个回答

如果您有在运行前不会更改的常量,请在头文件中声明它们:

//constants.hpp
#ifndef PROJECT_NAME_constants_hpp
#define PROJECT_NAME_constants_hpp
namespace constants {
  constexpr double G        = 6.67408e-11;
  constexpr double M_EARTH  = 5.972e24;
  constexpr double GM_EARTH = G*M_EARTH; 
}
#endif

//main.cpp
using namespace constants;
auto f_earth = GM_EARTH*m/r/r;  //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too

您想要这样做的原因是它允许编译器在运行时之前提前计算常量值,如果您有很多常量值,这很好。

您还可以使用一个简单的类来传递值:

class Params {
 public:
  double a,b,c,d;
  Params(std::string config_file_name){
    //Load configuration here
  }
};

void Foo(const Params &params) {
  ...
}

int main(int argc, char **argv){
  Params params(argv[1]);
  Foo(params);
}

另一个可能符合您思路的替代方法是使用命名空间(或嵌套命名空间)来正确分组常量。一个例子可能是:

namespace constants {
   namespace earth {
      constexpr double G = 6.67408e-11;
      constexpr double Mass_Earth = 5.972e24;
      constexpr double GM = G*Mass_Earth;
   }// constant properties about Earth

   namespace fluid {
      constexpr double density = 0.999; // g/cm^3
      constexpr double dyn_viscosity = 1.6735; //mPa * s
   }// constants about fluid at 2C

   // ... 

} // end namespace for constants

使用上述技术,您可以将引用常量本地化到一些所需的文件和名称空间,使它们比全局变量更受控制,同时获得一些类似的好处。当你使用常量时,它很简单:

constexpr double G_times_2 = 2.0*constants::earth::G;

如果您不喜欢嵌套命名空间的长链,您可以在必要时使用命名空间别名来缩短内容:

namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;

我做的一种方法是使用单例。

当您启动您的程序时,您启动您的单例并用常量数据填充它(可能来自您为运行而拥有的属性文件)。您可以在每个需要这些值的类中获得它并使用它。