在 C 中打印浮点数,同时避免变量参数提升为 double

发布于 2024-10-29 12:55:34 字数 554 浏览 10 评论 0原文

如何在 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

I have相对较少的处理能力(72MHz ARM Cortex-M3),并且我肯定在 ASCII 上遇到瓶颈浮点数据的输出。由于该架构一开始就缺乏硬件 FPU,因此必须在单精度和双精度之间进行转换并没有什么帮助。

有没有办法在直接 C 中更有效地打印浮点数?

How can I print (that is, to stdout) a float in C without having it be promoted to a double when passed to printf?

The issue here is that variadic functions in C promote all float parameter to double, which incurs two unnecessary conversions. For example, if you turn on -Wdouble-promotion in GCC and compile

float f = 0.f;
printf("%f", f);

you will get

warning: implicit conversion from 'float' to 'double' when passing argument to function

I have relatively little processing power to play with (a 72MHz ARM Cortex-M3), and I am definitely bottlenecking on ASCII output of floating point data. As the architecture lacks a hardware FPU to begin with, having to convert between single and double precision does not help matters.

Is there a way to print a float more efficiently in straight C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

江心雾 2024-11-05 12:55:34

避免提升不会为您节省任何东西,因为内部 double (或更可能的 long double)算术 printf 将执行的消耗量为至少 1000 倍的时间。准确地打印浮点值并不容易

如果您不关心准确性,而只需要快速打印近似值,则可以滚动自己的循环来进行打印。只要您的值不是太大而无法适合整数类型,请首先将非小数部分转换为整数并打印,然后减去该值并循环乘以 10,然后去掉整数部分以打印小数部分一次一位数字(将其缓冲在字符串中以获得更好的性能)。

或者你可以这样做:

printf("%d.%.6d", (int)x, (int)((x-(int)x)*1000000));

Avoiding the promotion will not save you anything, since the internal double (or more likely long double) arithmetic printf will perform is going to consume at least 1000x as much time. Accurately printing floating point values is not easy.

If you don't care about accuracy though, and just need to print approximate values quickly, you can roll your own loop to do the printing. As long as your values aren't too large to fit in an integer type, first convert and print the non-fractional part as an integer, then subtract that off and loop multiplying by 10 and taking off the integer part to print the fractional part one digit at a time (buffer it in a string for better performance).

Or you could just do something like:

printf("%d.%.6d", (int)x, (int)((x-(int)x)*1000000));
请爱~陌生人 2024-11-05 12:55:34

不幸的是,printf 不支持处理普通的 float:s。

这意味着您必须编写自己的打印函数。如果您不需要 printf 的完整表达能力,您可以轻松地将浮点值转换为整数部分和表示小数位数的部分,并使用整数打印出来。

另一方面,如果您只是想摆脱警告,则可以将 float 显式转换为 double

Unfortunately, printf does not have support for handing plain float:s.

This mean that you would have to write your own print function. If you don't need the full expressive power of printf, you could easily convert your floating-point value to an integral part and a part representing a number of decimals, and print out both using integers.

If, on the other hand, you simply would like to get rid of the warning, you could explicitly cast the float to a double.

深空失忆 2024-11-05 12:55:34

我认为这并不重要 - printf 已经是一件非常耗时的令人讨厌的事情了,那些转换应该不重要。将 float 转换为 double 的时间应该远远少于将任何数字转换为 ascii 的时间(您应该/可以分析您的代码以获得明确的答案)。唯一剩下的解决方案是编写一个自己的自定义输出例程,该例程将 float->ascii 转换,然后使用 put (或类似的)。

I think that doesnt matter - printf is already such a timeconsuming nasty thing, that those conversion should not matter. The time converting float to double should be far less than converting any number to ascii (you should/could profile your code to get there a definitve answer). The only remaining solution would be to write an own custom output routine which converts float->ascii and then uses puts (or similar).

流年里的时光 2024-11-05 12:55:34
  • 第一种方法:使用 ftoa 代替 printf。配置文件。

  • 为了提高输出灵活性,我将进入编译器 stdlib 的源代码,也许是 gcc 的一些衍生代码,找到 printf 实现并复制 double -> 的相关代码。 ascii 转换。将其重写为 float -> 。

  • 接下来,手动将一两个重要调用站点更改为您的新(非可变)版本并对其进行分析。

  • 如果它解决了您的问题,您可以考虑根据 stdlib 的版本重写您自己的 printf,从而传递 float* 而不是 float。这应该摆脱自动提升。

  • First approach: Use ftoa instead of printf. Profile.

  • For increased output flexibility, I would go into the source code of your compiler's stdlib, perhaps some derivative of gcc anyway, locate the printf implementation and copy over the relevant code for double -> ascii conversion. Rewrite it to float -> ascii.

  • Next, manually change one or two porminent call-sites to your new (non-variadic) version and profile it.

  • If it solves your problem, you could think of rewriting your own printf, based on the version from stdlib, whereby instead of float you pass float*. That should get rid of the automatic promotion.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文