C printf %a 和 %La

标签 c hex printf type-conversion

我必须使用 C 重新实现 printf(3),而不使用任何可以为我进行转换的函数。

在我理解了 感谢各位 %a 的工作原理后,我以为我已经完成了:How %a conversion work in printf statement?

然后我意识到我不明白舍入是如何完成的所以我问:C printf float rounding然后认为在你帮助我之后我就完成了。

现在 %a 完全像官方的一样工作,我认为 %La 会和 %a 完全一样,但是用 long double 因为那个人只说:

Modifier a, A, e, E, f, F, g, G

l (ell) double (ignored, same behavior as without it)
L long double

我发现它输出的东西完全不同:'(

double a_double = 0.0001;
long double a_long_double = 0.0001;
printf("%a\n", a_double); #=> 0x1.a36e2eb1c432dp-14
printf("%La\n", a_long_double); #=> 0xd.1b71758e21968p-17

%a 结果总是以 1. 开头,现在我完全不明白 %La 在做什么。

你能帮我理解将 0.0001 转换为 0xd.1b71758e21968p-17过程吗?

编辑:我真正不明白的部分是为什么 %a 总是输出以1. 开头的内容,而不是%La ?

EDIT2:更准确地说:为什么 %a 选择输出 1。 ...p-14%La 选择输出 d。 ...p-17 ?

最佳答案

任何(有限的,非零的) float 都有四个不同的(有效的)十六进制浮点表示:

  1. 最高十六进制数在8到F之间
  2. 另一个最大的十六进制数在 4 到 7 之间
  3. 另一个最高十六进制数是2或3
  4. 另一个最高十六进制数是1

并且它们具有连续递增的指数值。您可以使用右移从一个传递到另一个;这个过程可能会向右增加另一个数字; C 标准中没有关于您应该为 %a 转换使用哪种表示的限制。

使用 IEEE float(24 位有效数)或通常的双扩展(64 位有效数,与 i386 Linux 上的 long double 一样),因为位数可以被 4 整除,所以它通常对规范化数字使用第一种形式,因为它是使用最少的十六进制数字来完整表示数字的形式(分别是 十六进制 之后的 5 和 15 位数字。)。

另一方面,对于 IEEE double(53 位有效数),在点 之后使用第四种形式和 13 个十六进制数字看起来更好。:因此所有显示的数字实际上都代表数据。 IEEE quad(正式名称为 binary128,113 位有效数)也会发生同样的情况,点后有 28 个十六进制数字。

这些表示还具有与数字的内存表示相匹配的良好属性(这就是 C99 标准中的脚注指导实现这样做的原因。)

如果我们现在查看您的问题,第一个示例 (double) 符合上述准则,第一个数字是 1,点后是 13 个十六进制数字。

第二个例子更狡猾。首先,double 常量存储到 long double 变量中:根据编译器的不同,常量可能会四舍五入到 double 的精度(如好像是在这里完成的。)这意味着第53位之后的位将全为零。然后使用%La转换,同样按照上面的指导方针,因此选择第一个表示,以D开头(二进制为1101xxx,与转换为11010xxx的1.A进行比较);这里也只有 13 个十六进制数字,因为编译器丢弃了打印不必要的零(由于四舍五入。)

请注意,您不能将 printf%a 转换为 float

关于C printf %a 和 %La,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29171386/

相关文章:

c - 可等待定时器复位周期

c - 循环的执行时间

c - systemcalls.h 找不到这样的文件或目录

将 Char * 缓冲区转换为十六进制以便在 c 中打印

python - 如何打印变量之间的空格?

c - C strtok() 中的字符串拆分

Java:文件到十六进制?

python - 装饰十六进制函数以填充零

c - 自动交互编程

C++ 相当于 sprintf?