[英]How can I make this expression involving floating-point functions a compile-time constant?
I have a constant integer, steps, which is calculated using the floor function of the quotient of two other constant variables.我有一个常数 integer,步骤,它是使用其他两个常数变量的商的下限 function 计算的。 However, when I attempt to use this as the length of an array, visual studio tells me it must be a constant value and the current value cannot be used as a constant.
但是,当我尝试将其用作数组的长度时,Visual Studio 告诉我它必须是一个常量值,并且当前值不能用作常量。 How do I make this a "true" constant that can be used as an array length?
如何使其成为可用作数组长度的“真实”常量? Is the floor function the problem, and is there an alternative I could use?
地板 function 有问题吗?我可以使用其他替代方案吗?
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];
};
It is not possible with the standard library's std::pow
and std::floor
function, because they are not constexpr
-qualified.标准库的
std::pow
和std::floor
function 是不可能的,因为它们不是constexpr
限定的。
You can probably replace std::pow
with a hand-written implementation my_pow
that is marked constexpr
.您可能可以用标记为
constexpr
的手写实现my_pow
替换std::pow
。 Since you are just trying to take the power of integers, that shouldn't be too hard.既然你只是想利用整数的力量,那应该不会太难。 If you are only using powers of 10, floating point literals may be written in the scientific notation as well, eg
1e7
, which makes the pow
call unnecessary.如果您只使用 10 的幂,浮点文字也可以用科学记数法编写,例如
1e7
,这使得pow
调用变得不必要。
The floor
call is not needed since float
/ double
to int
conversion already does flooring implicitly.由于
float
/ double
到int
的转换已经隐式地进行了floor
调用,因此不需要地板调用。 Or more correctly it truncates , which for positive non-negative values is equivalent to flooring.或者更准确地说,它会截断,对于正非负值,这相当于地板。
Then you should also replace the const
with constexpr
in the variable declarations to make sure that the variables are usable in constant expressions:然后你还应该在变量声明中用
constexpr
替换const
以确保变量在常量表达式中可用:
constexpr int simlength = 3.154*my_pow(10,7); // or `3.154e7`
constexpr float timestep = 100;
constexpr int steps = simlength / timestep;
Theoretically only float
requires this change, since there is a special exception for const
integral types, but it seems more consistent this way.理论上只有
float
需要这种改变,因为const
整数类型有一个特殊的例外,但这种方式似乎更一致。
Also, I have a feeling that there is something wrong with the types of your variables.另外,我感觉你的变量类型有问题。 A length and steps should not be determined by floating-point operations and types, but by integer types and operations alone.
长度和步长不应由浮点运算和类型决定,而应仅由 integer 类型和运算决定。 Floating-point operations are not exact and introduce errors relative to the mathematical precise calculations on the real numbers.
浮点运算不是精确的,并且相对于对实数的数学精确计算会引入错误。 It is easy to get unexpected off-by-one or worse errors this way.
这样很容易出现意外的错误或更严重的错误。
You cannot define an array of a class type before defining the class.在定义 class 之前,您不能定义 class 类型的数组。
Solution: Define body
before defining bodies
.解决方案:定义
body
之前定义bodies
。
Furthermore, you cannot use undefined names.此外,您不能使用未定义的名称。
Solution: Define bcount
before using it as the size of the array.解决方案:在使用之前定义
bcount
作为数组的大小。
Is the floor function the problem, and is there an alternative I could use?
地板 function 有问题吗?我可以使用其他替代方案吗?
std::floor
is one problem. std::floor
是一个问题。 There's an easy solution: Don't use it.有一个简单的解决方案:不要使用它。 Converting a floating point number to integer performs similar operation implicitly (the behaviour is different in case of negative numbers).
将浮点数转换为 integer 隐式执行类似的操作(在负数的情况下行为不同)。
std::pow
is another problem. std::pow
是另一个问题。 It cannot be replaced as trivially in general, but in this case we can use a floating point literal in scientific notation instead.一般来说,它不能被简单地替换,但在这种情况下,我们可以使用科学计数法中的浮点文字来代替。
Lastly, non-constexpr floating point variable isn't compile time constant.最后,非 constexpr 浮点变量不是编译时间常数。 Solution: Use
constexpr
.解决方案:使用
constexpr
。
Here is a working solution:这是一个有效的解决方案:
constexpr int simlength = 3.154e7;
constexpr float timestep = 100;
constexpr int steps = simlength / timestep;
PS trace
is a very large array. PS
trace
是一个非常大的数组。 I would recommend against using so large member variables, because it's easy for the user of the class to not notice such detail, and they are likely to create instances of the class in automatic storage.我建议不要使用如此大的成员变量,因为 class 的用户很容易不会注意到这些细节,而且他们很可能会在自动存储中创建 class 的实例。 This is a problem because so large objects in automatic storage are prone to cause stack overflow errors.
这是一个问题,因为自动存储中这么大的对象很容易导致堆栈溢出错误。 Using
std::vector
instead of an array is an easy solution.使用
std::vector
代替数组是一个简单的解决方案。 If you do use std::vector
, then as a side effect the requirement of compile time constant size disappear and you will no longer have trouble using std::pow
etc.如果您确实使用了
std::vector
,那么作为副作用,编译时间常数大小的要求消失了,您将不再有使用std::pow
等的问题。
Because simlength
is 3.154*10-to-the-7th
, and because timestep
is 10-squared, then the steps
variable's value can be written as:因为
simlength
是3.154*10-to-the-7th
,并且因为timestep
是 10 平方,所以steps
变量的值可以写成:
3.154e7 / 1e2 == 3.154e5
And, adding a type-cast, you should be able to write the array as:并且,添加一个类型转换,您应该能够将数组编写为:
double trace[2][(int)(3.154e5)];
Note that this is HIGHLY IRREGULAR, and should have extensive comments describing why you did this.请注意,这是非常不规则的,并且应该有广泛的评论来描述您为什么这样做。
Try switching to constexpr
:尝试切换到
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];
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.