如何使这个涉及浮点函数的表达式成为编译时常量?

How can I make this expression involving floating-point functions a compile-time constant?

我有一个常量整数 steps,它是使用其他两个常量变量的商的 floor 函数计算的。但是,当我尝试将其用作数组的长度时,visual studio 告诉我它必须是一个常量值,而当前值不能用作常量。如何使它成为可用作数组长度的“真实”常量? floor 函数是否有问题,我可以使用替代方法吗?

const int simlength = 3.154*pow(10,7);
const float timestep = 100;
const int steps = floor(simlength / timestep);

struct body bodies[bcount];

struct body {
    string name;
    double mass;
    double position[2];
    double velocity[2];
    double radius;
    double trace[2][steps];
};

您不能在定义 class.

之前定义 class 类型的数组

解决方法:先定义body再定义bodies.


此外,您不能使用未定义的名称。

解决方法:先定义bcount再作为数组的大小


Is the floor function the problem, and is there an alternative I could use?

std::floor 是一个问题。有一个简单的解决方案:不要使用它。将浮点数转换为整数会隐式执行类似的操作(负数时行为不同)。

std::pow 是另一个问题。一般情况下,它不能被简单地替换,但在这种情况下,我们可以使用科学计数法中的浮点文字来代替。

最后,非 constexpr 浮点变量不是编译时常量。解决方法:使用constexpr.

这是一个可行的解决方案:

constexpr int simlength = 3.154e7;
constexpr float timestep = 100;
constexpr int steps = simlength / timestep;

P.S。 trace 是一个非常 的大数组。我建议不要使用这么大的成员变量,因为 class 的用户很容易不会注意到这些细节,他们很可能会在自动存储中创建 class 的实例。这是一个问题,因为自动存储中如此大的对象很容易导致堆栈溢出错误。使用 std::vector 而不是数组是一个简单的解决方案。如果你确实使用 std::vector,那么作为副作用,编译时间常量大小的要求就会消失,你将不再有使用 std::pow

的问题

因为simlength3.154*10-to-the-7th,又因为timestep是10的平方,那么steps变量的值可以写成:

3.154e7 / 1e2 == 3.154e5

并且,添加类型转换,您应该能够将数组写为:

double trace[2][(int)(3.154e5)];

请注意,这是非常不规则的,应该有大量评论来说明您这样做的原因。

尝试切换到 constexpr:

constexpr int   simlength = 3.154e7;
constexpr float timestep  = 1e2;
constexpr int   steps     = simlength / timestep;

struct body {
    string name;
    double mass;
    double position[2];
    double velocity[2];
    double radius;
    double trace[2][steps];
};

标准库的 std::powstd::floor 函数是不可能的,因为它们不是 constexpr 限定的。

您或许可以用标记为 constexpr 的手写实现 my_pow 替换 std::pow。由于您只是想获取整数的幂,所以应该不会太难。如果您只使用 10 的幂,浮点文字也可以用科学记数法书写,例如1e7,这使得 pow 调用变得不必要。

不需要 floor 调用,因为 float/doubleint 的转换已经隐含地进行了 flooring。或者更准确地说,它 截断 ,对于正非负值,它等同于 flooring。

那么你也应该在变量声明中用constexpr替换const以确保变量在常量表达式中可用:

constexpr int simlength = 3.154*my_pow(10,7); // or `3.154e7`
constexpr float timestep = 100;
constexpr int steps = simlength / timestep;

理论上只有 float 需要此更改,因为 const 整数类型有一个特殊的例外,但这样看起来更一致。

另外,我感觉你的变量类型有问题。 lengthsteps 不应由浮点运算和类型确定,而应仅由整数类型和运算确定。浮点运算并不精确,相对于实数的数学精确计算会引入误差。这样很容易出现意想不到的差一或更糟的错误。