如何在 C 中打印(即到标准输出)float,而不在传递给 printf 时将其提升为 double?
这里的问题是 C 中的可变参数函数将所有 float 参数提升为 double,这会导致两次不必要的转换。例如,如果您在 GCC 中打开 -Wdouble-promotion 并编译
float f = 0.f;
printf("%f", f);
你将会得到
warning: implicit conversion from 'float' to 'double' when passing argument to function
我的处理能力相对较小(72MHz ARM Cortex-M3),而且我在浮点数据的 ASCII 输出上肯定遇到了瓶颈。由于该架构一开始就缺乏硬件 FPU,因此必须在单精度和双精度之间进行转换并没有什么帮助。
有没有办法在直接 C 中更有效地打印浮点数?
避免升级不会为你节省任何东西,因为内部
double
(或更可能是 long double
)算术 printf
将执行至少 1000 倍的时间。准确打印浮点值并不容易。
如果您不关心准确性,而只需要快速打印近似值,您可以滚动自己的循环来进行打印。只要您的值不是太大而无法适合整数类型,请首先将非小数部分转换为整数并打印,然后减去该值并循环乘以 10,然后去掉整数部分以打印小数部分一次一位数字(将其缓冲在字符串中以获得更好的性能)。
或者你可以这样做:
printf("%d.%.6d", (int)x, (int)((x-(int)x)*1000000));
不幸的是,
printf
不支持处理普通浮动:s。
这意味着您必须编写自己的打印函数。如果您不需要
printf
的完整表达能力,您可以轻松地将浮点值转换为整数部分和代表小数位数的部分,并使用整数打印出来。
另一方面,如果您只是想摆脱警告,则可以显式地将
float
转换为 double
。
我认为这并不重要 - printf 已经是一件非常耗时的令人讨厌的事情了,那些转换应该不重要。将 float 转换为 double 的时间应该远远少于将任何数字转换为 ascii 的时间(您应该/可以分析您的代码以获得明确的答案)。唯一剩下的解决方案是编写一个自己的自定义输出例程,该例程将 float->ascii 转换,然后使用 put (或类似的)。
第一种方法:使用ftoa代替printf。简介.
为了增加输出灵活性,我将进入编译器 stdlib 的源代码,也许是 gcc 的一些衍生代码,找到 printf 实现并复制相关代码以进行 double -> ascii 转换。将其重写为 float -> ascii。
接下来,手动将一两个重要的调用站点更改为您的新(非可变)版本并对其进行分析。
如果它解决了您的问题,您可以考虑基于 stdlib 的版本重写您自己的 printf,从而传递 float* 而不是 float。那应该摆脱自动促销。
可能以不好的方式:为 float 变量添加包装器以将它们作为 int32 传递
#define FTI32(val) *((int32_t*)&val)
使用自定义格式化程序库,例如 xformatc.c 编辑浮点部分:
param.dbl = (DOUBLE) va_arg(args, DOUBLE_ARGS);
替换为:
int fint = va_arg(args, int);
param.dbl = *((float*)(&fint));