如何使用 printf 打印单精度浮点数 [英] How to print a single-precision float with printf

查看:72
本文介绍了如何使用 printf 打印单精度浮点数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 x86_64 程序集中打印一个浮点数,但它只是将值打印为零.

I'm trying to print a floating point number in x86_64 assembly but it just prints the value as zero.

关于这个已经有几个问题了.一个似乎通过确保您在 %al 中设置您使用的向量寄存器的数量来解决.另一个显示您需要有 16 个字节的堆栈对齐.但是,我正在做这两件事,但仍然没有得到正确的输出.

There's a few questions about this already. One appeared to be resolved by ensuring that you set the number of vector registers you're using in %al. Another showed that you need to have a stack alignment of 16 bytes. But, I'm doing both those things and still not getting correct output.

这是我的程序:

# prints a floating point value
.section .rodata
.fmt: .string "num: %f
"
.num: .float 123.4

.section .text
.global main
.type   main, @function
main:
  subq $8, %rsp     # 16-byte alignment

  # print my number
  movss .num, %xmm0 # load float value
  movq $.fmt, %rdi  # load format string
  movb $1, %al      # use 1 vector register
  call printf

  # exit
  addq $8, %rsp     # undo alignment
  movq $0, %rax     # return 0
  ret

推荐答案

printf(3)%f 格式说明符需要 double.没有办法让 printf 接受 float,只有 doublelong double.

printf(3)'s %f format specifier wants a double. There is no way to get printf to accept a float, only double or long double.

C 的默认参数提升 指定对诸如 foo(char *fmt, ...) 等可变参数函数的调用将 float 提升为 double,并将窄整数类型的通常整数提升为 int,用于匹配原型的 ... 部分的尾随参数.(这同样适用于调用没有原型的函数的所有参数.)N1570 6.5.2.2 函数调用,第 6 和 7 小节.

C's default argument promotions specify that calls to variadic functions like foo(char *fmt, ...) promote float to double, and perform the usual integer promotions of narrow integer types to int, for trailing args that match the ... part of the prototype. (The same applies to all args for calling functions with no prototype.) N1570 6.5.2.2 Function calls, subsections 6 and 7.

因此 C 没有为调用者提供将 float 传递给 printf 的方法,因此它没有对其进行转换,并且 %f 表示 double.(%lf 也适用于 double,假设实现忽略非整数/wchar_t 转换.接受 %lf for double 在 C99/C11 和C++11 printf 实现,因此您可以安全地使用相同的 %lf 格式字符串和 double 用于 printfscanf).

Thus C provides no way for a caller to pass a float to printf, so it has no conversion for it, and %f means double. (%lf also works for double, assuming the implementation ignores it for non-integer / wchar_t conversions. Accepting %lf for double is required in C99/C11 and C++11 printf implementations, so you can safely use the same %lf format string with a double for printf and scanf).

请注意,scanf 是不同的,因为 float *double * 不受这些促销的影响.

Note that scanf is different, because float * and double * aren't affected by those promotions.

如果你看看 编译器输出,你会看到 gcc 做你所做的一切,并且 pxor 首先将寄存器归零以打破对旧值的错误依赖%xmm0.(cvtss2sd 糟糕的设计让目标不变.)gcc 错误在谨慎的一面,并在许多情况下插入异或归零指令以打破错误的依赖关系.

If you look at compiler output, you'll see gcc do everything you did, and pxor-zero the register first to break the false dependency on the old value of %xmm0. (cvtss2sd's poor design leaves the upper 64 bits of the destination unchanged.) gcc errs on the side of caution, and inserts xor-zeroing instructions to break false dependencies in many cases.

您可能得到 0,因为 xmm0 的高位恰好为零.当 printf 将 xmm0 的低 64 位视为 double(x86 上的 IEEE binary64),它在尾数的低 32 位中找到 123.4f 的位模式,其余为零.作为一个 64 位 double,这个位模式代表一个非常小的(次正规)数,所以它与 %f 一起显示为零.

You're probably getting 0 because the upper bits of xmm0 happen to be zero. When printf looks at the low 64 bits of xmm0 as a double (IEEE binary64 on x86), it finds the bit pattern for 123.4f in the low 32 bits of the mantissa, and the rest zero. As a 64-bit double, this bit-pattern represents a very small (subnormal) number, so it comes out as zero with %f.

您可以尝试使用 float 的等效项(例如在 http://www.h-schmidt.net/FloatConverter/IEEE754.html),在低半部分设置一些位,看看你得到了什么.

You can try the equivalent with a float, (e.g. on http://www.h-schmidt.net/FloatConverter/IEEE754.html), setting some bits in the low half to see what you get.

如果您使用了 %g(科学记数法)或 %a(double 位模式的十六进制表示),则非零位会出现.(除非您在 MXCSR 中启用了非正规数为零模式.)

If you used %g (scientific notation) or %a (hex representation of the double bit-pattern), the non-zero bits would show up. (Unless you had Denormals Are Zero mode enabled in the MXCSR.)

这篇关于如何使用 printf 打印单精度浮点数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆