- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我必须使用 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 都有四个不同的(有效的)十六进制浮点表示:
并且它们具有连续递增的指数值。您可以使用右移从一个传递到另一个;这个过程可能会向右增加另一个数字; 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/
我是一名优秀的程序员,十分优秀!