printf语句中转换的百分比如何?

Its*_*ret 10 c printf hex data-conversion

也许这不属于SO,但我不知道在哪里.

我不得不重新实现printf(3)C不使用,会做的转换对我有什么功能,我几乎做了,但我坚持上%a,我真的不明白发生了什么位置,例如:

printf("%a\n", 3.0); //#=> 0x1.8p+1
printf("%a\n", 3.1); //#=> 0x1.8cccccccccccdp+1
printf("%a\n", 3.2); //#=> 0x1.999999999999ap+1
printf("%a\n", 3.3); //#=> 0x1.a666666666666p+1
printf("%a\n", 3.4); //#=> 0x1.b333333333333p+1
printf("%a\n", 3.5); //#=> 0x1.cp+1
printf("%a\n", 3.6); //#=> 0x1.ccccccccccccdp+1
Run Code Online (Sandbox Code Playgroud)

我当然读到了那个说:

double参数被舍入并在样式[ - ] 0xh.hhhp [+ - ] d中转换为十六进制表示法,其中十六进制点字符后面的位数等于精度规范.

但是,这并不能真正帮助我不明白的过程是转换3.21.999999999999ap+1

我不需要任何代码,但更多的解释.

PS:如果这不是这个问题的地方,你可以指引我到正确的地方吗?

编辑:虽然@juhist答案适用于数字> = 1.0它没有解释如何获得0.0et 之间的数字结果1.0:

printf("%a\n", 0.01); //#=> 0x1.47ae147ae147bp-7
printf("%a\n", 0.1);  //#=> 0x1.999999999999ap-4
printf("%a\n", 0.2);  //#=> 0x1.999999999999ap-3
printf("%a\n", 0.3);  //#=> 0x1.3333333333333p-2
printf("%a\n", 0.4);  //#=> 0x1.999999999999ap-2
printf("%a\n", 0.5);  //#=> 0x1p-1
printf("%a\n", 0.6);  //#=> 0x1.3333333333333p-1
Run Code Online (Sandbox Code Playgroud)

另外,我真的希望The "a" near the end occurs due to limited floating point calculation precision有关转换的精确度:printf("%a\n", 3.2); //#=> 0x1.999999999999ap+1

编辑2:现在最后一个谜是解释为什么在这种情况下:

printf("%a\n", 0.1); //#=> 0x1.999999999999ap-4
Run Code Online (Sandbox Code Playgroud)

最后9成为和a在这种情况下:

printf("%a\n", 0.3); //#=> 0x1.3333333333333p-2
Run Code Online (Sandbox Code Playgroud)

最后一次3停留3

hac*_*cks 4

首先你要知道这个表示是什么0xh.hhhh p\xc2\xb1d,意思?我们以十六进制常量为例来理解一下0x1.99999ap+1
\n1小数点之前的数字是十六进制数字,其后面 ( 99999a) 的十六进制数字的个数等于精度。0x是十六进制引入器,p是指数字段。指数是一个十进制数,表示2有效部分所乘的幂。

\n\n

因此,当0x1.99999ap+1与 then 相乘时21,它将转换为3.2十进制。回想一下如何1.55e+1转换为15.500000十进制。类似的事情也在这里发生。

\n\n

0x1.99999ap+1现在您需要了解to转换背后的数学原理3.2。这将按如下方式进行

\n\n
\n

1*16 0 + 9*16 -1 + 9*16 -2 + 9*16 -3 + 9*16 -4 + 9*16 -5 + 10*16 -1

\n
\n\n

(以十进制表示)等于

\n\n
 1.60000002384185791015625  \n
Run Code Online (Sandbox Code Playgroud)\n\n

您只需要最多 1 个精度。因此,将1.6其乘以21。这会给3.2.

\n\n

要进行上述过程的相反过程,您需要找到2浮点数除以的幂以获得1小数点前的数字。之后使用连续乘法将小数部分更改为十六进制分数。请按如下方式进行:

\n\n
\n

    \n
  1. 3.2/2 1 = 1.6
  2. \n
  3. 对1.6取整数部分,得到1小数点前的十六进制数字。
  4. \n
  5. 乘以。.616得到的整数部分将成为十六进制分数中的数字。对获得的小数部分重复此步骤,直至达到所需的精度(默认为 6)。

    \n\n

    \n
      \n
    • .6 * 16 = 9.6 ---> 整数部分 = 9 小数部分 = .6
    • \n
    • .6 * 16 = 9.6 ---> 整数部分 = 9 小数部分 = .6
    • \n
    • .6 * 16 = 9.6 ---> 整数部分 = 9 小数部分 = .6
    • \n
    • .6 * 16 = 9.6 ---> 整数部分 = 9 小数部分 = .6
    • \n
    • .6 * 16 = 9.6 ---> 整数部分 = 9 小数部分 = .6
    • \n
    • .6 * 16 = 9.6 ---> 整数部分 = 9 小数部分 = .6
    • \n
\n\n
\n\n\n

因此,十六进制小数将变为.999999\n现在将十六进制指示符0x、小数点前的十六进制数字和得到的十六进制小数以及指数字段结合起来即可得到结果。

\n\n
\n

3.2 10 = 0x1.999999p+1 16

\n
\n\n

同样,您可以获得小于 . 的数字的十六进制浮点数1.0,例如0.01。在这种情况下,要获得小数点前的十六进制数字,1您需要将其除以 的幂2。因为128(2 5 ) 乘以 后将得到整数部分为,0.01的数。这意味着您需要乘以1/2 -5,或者您可以说您需要将其除以 2 -5才能得到。现在应用上述步骤 2 和 3。1128*.01 = 1.280.011.28

\n