如何在使用GCC或/和IAR编译时禁用双精度数学运算?

8

我的嵌入式 C 代码运行在单精度 Cortex M4F 上,它有一个单精度 FPU。我关心编译器在像 这样的地方 经常放置基于软件的双精度数学操作。

float_var1 = 3.0 * int_var / float_var_2;
(3.0 instead of 3.0f)

我担心会错过一些双精度常量。如何定位所有较慢的双精度数学运算?使用sourcery GCC或IAR禁用双精度或生成错误/警告即可。

请指导我实现我的目标的正确方法。

3个回答

13

我该如何查找所有较慢的双精度数学运算?在sourcery GCC或IAR中禁用双精度或生成错误/警告会做到这一点。

-Wdouble-promotion正好可以满足你的要求,请参阅文档中的警告选项。顺便说一下,文档中的示例与你的情况非常相似。

以下基本上是你的示例:

float f(int int_var, float float_var_2) {
  return 3.0 * int_var / float_var_2;
}

如果我在gcc中传递-Wdouble-promotion标志,会发生什么:

gcc -c -Wdouble-promotion float.c
float.c: In function ‘f’:
float.c:2:24: warning: implicit conversion from ‘float’ to ‘double’ to match other operand of binary expression [-Wdouble-promotion]

如果您还传递-Werror标志,则可以将所有警告转换为错误。如果这太严格了,您可以通过传递-Werror=foo选择性地将警告转换为错误,请参见文档中的警告选项


在使用“-Werror”参数时,要明智地使用它:不要盲目地将所有警告转换为错误,而是针对特定的警告进行处理:“-Werror=double-promotion”。否则,您的程序可能会因为新编译器版本而无法编译。 - Ruslan

7

gcc有一个优化选项-fsingle-precision-constant,将普通浮点常量视为单精度浮点数:

-fsingle-precision-constant

将浮点常量视为单精度浮点数,而不是隐式转换为双精度浮点常量。


3

作为快速解决方案,请尝试按照以下步骤进行:

  1. 在每个浮点常量后面添加后缀 f:1.3f、3.1415f 等。
  2. 仅使用 float 变量。
    即使编译器进行了中间高精度计算,最终结果也会被截断为 float 的精度。
  3. 请注意,类型 floatdoublelong double 都试图遵循浮点标准 ISO/IEC/IEEE 60559 中所执行的规则。
    请参阅:C 中的浮点标准
    类型 float 旨在成为 单精度浮点数
    类型 double 旨在成为 双精度浮点数
    类型 long double 旨在成为 扩展精度浮点数
  4. 在您的计算的相关部分中进行 (float) 强制转换。
  5. 使用带有后缀 "f" 的 <math.h> 函数,
    这些函数旨在接受和返回 float 类型的值。

然而,所有先前的建议都只是推荐。
有时编译器会在 long double 的精度下进行中间计算。
此信息可以从 <float.h> 标头中存在的宏中检索。
例如:

   FLT_EVAL_METHOD  // gives information about the method used in intermediate evaluations  
   FLT_ROUNDS       // gives information about the rounding method  

也许,要调整浮点数计算的行为,您需要更深入地了解您特定编译器的选项。

这不是一个“快速解决方案”。OP提出问题是为了帮助他避免所有(或部分)的麻烦。 - anatolyg
同意。这似乎是一个老问题。不能对自己的答案进行踩。 - pablo1977

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接