如何在%printf语句转换工作? [英] How %a conversion work in printf statement?

查看:176
本文介绍了如何在%printf语句转换工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

也许这不属于对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

当然,我读到那个男子说:


  

双参数四舍五入并转换为十六进制
  在款式[ - ] 0xh.hhhp [+ - ] d,其中数字后面的数字
  十六进制点字符等于precision规范。


但是,这并不能真正帮助我不明白的过程的那个变换 3.2 1.999999999999ap + 1

我不需要任何code,但实际上更多的解释。

PS:如果这不是地方这个问题,你可以点我到正确的位置。

编辑:在 @juhist 答案适用于数> = 1.0 它没有解释如何获得导致对之间的数字 0.0 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

此外,我真的很喜欢在这样的precision 将A接近尾声的发生是由于有关转换有限浮点计算precision: 的printf(%A \\ N,3.2); //#=> 0x1.999999999999ap + 1

EDIT2:现在最后之谜是解释为什么在这种情况下:

 的printf(%A \\ N,0.1); //#=> 0x1.999999999999ap-4

最后一个 9 变得和 A 在这种情况下:

 的printf(%A \\ N,0.3); //#=> 0x1.3333333333333p-2

最后一个 3 保持一个 3


解决方案

首先,你需要知道的再presentation 0xh.hhhh p±D,意思?让我们通过采取十六进制常数的例子理解 0x1.99999ap + 1 。结果
数字 1 前的小数点是一个十六进制数字和数字
后其十六进制数字( 99999a )等于precision。 0X 是十六进制引导和 P 是指数字段。该指数是一个十进制数,表示通过该显著部分将倍增 2 的力量。

所以,当 0x1.99999ap + 1 2 相乘 1 那么这将十进制转换为 3.2 。回想一下,如何 1.55e + 1 十进制转换为 15.500000 。类似的事情发生在这里。

现在,你需要知道 0x1.99999ap + 1 的转换背后的数学 3.2 。这将进行如下:


  

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


这是(十进制)等于

  1.60000002384185791015625

您只需要到1 precision。因此,采取 1.6 2 1 。这将给 3.2

要到你需要找到 2 的权重,据此浮点数将被划分到获得数字上面的过程 1 之前小数点。后使用连续乘法来改变的小数部分为十六进制分数。步骤如下:


  


      
  1. 3.2 / 2 1 = 1.6

  2.   
  3. 从1.6乘坐组成部分,以获得进制 1 小数点前。

  4.   
  5. 0.6 16 。该整数部分获得的意志变成了十六进制部分的数字。重复此步骤与所获得的小数部分所需的precision(6默认值)。结果


      
      

        

          
    • 0.6 * 16 = 9.6 --->积分部分= 9小数部分= 0.6

    •     
    • 0.6 * 16 = 9.6 --->积分部分= 9小数部分= 0.6

    •     
    • 0.6 * 16 = 9.6 --->积分部分= 9小数部分= 0.6

    •     
    • 0.6 * 16 = 9.6 --->积分部分= 9小数部分= 0.6

    •     
    • 0.6 * 16 = 9.6 --->积分部分= 9小数部分= 0.6

    •     
    • 0.6 * 16 = 9.6 --->积分部分= 9小数部分= 0.6

    •     

    
  

因此​​,十六进制分数将成为 0.999999
现在,小数点和指数字段一起获得得到的结果为十六进制部分结合之前六角指标 0X ,十六进制数字。


  

3.2 <子> 10 = 0x1.999999p + 1 16


同样可以获取十六进制浮点数不到数字1.0 ,例如 <0.01 / code>。在这种情况下取​​得两位数十六进制 1 之前,你需要将它与一个数字是 2 。由于 128 (2 5 )与相乘后的 <0.01 / code>将给予其组成部分的数量成为 1 128 * 0.01 = 1.28 。这意味着你需要乘 <0.01 / code> 1/2 -5 或者你可以说你需要除以2为 -5 获得 1.28 。现在应用步骤2和3如上所述。

Maybe this doesn't belong on SO but I don't know where else.

I have to reimplement printf(3) with C without using any function that would do the conversion for me, I'm nearly done, but I'm stuck on %a, I really don't understand what is happening here for example:

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

Of course I read the man which says:

The double argument is rounded and converted to hexadecimal notation in the style[-]0xh.hhhp[+-]d, where the number of digits after the hexadecimal-point character is equal to the precision specification.

But this doesn't really help I don't understand the process that transforms 3.2 to 1.999999999999ap+1

I don't need any code but really more an explanation.

PS: If this isn't the place for this question could you point me to the right place?

EDIT: While @juhist answer works for numbers >= 1.0 it doesn't explain how to get the result for numbers between 0.0 et 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

Also I would really like a precision on this The "a" near the end occurs due to limited floating point calculation precision concerning the conversion: printf("%a\n", 3.2); //#=> 0x1.999999999999ap+1

EDIT2: Now the last mystery is to explain why in this case:

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

The last 9 becomes and a and in this case:

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

The last 3 stays a 3?

解决方案

First you need to know what the representation 0xh.hhhh p±d, mean? Let's understand it by taking an example of hexadecimal constant 0x1.99999ap+1.
The digit 1 before the decimal point is a hex digit and the number of hexadecimal digits after it (99999a) is equal to the precision. 0x is the hex introducer and the p is exponent field. The exponent is a decimal number that indicates the power of 2 by which the significant part is multiplied.

So, when 0x1.99999ap+1 will be multiplied with 21 then it will be converted to 3.2 in decimal. Recall that how 1.55e+1 converted to 15.500000 in decimal. Similar thing is happening here.

Now you need to know the mathematics behind the conversion of 0x1.99999ap+1 to 3.2. This will proceed as follows

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

Which is (in decimal) equal to

 1.60000002384185791015625  

You need only up to 1 precision. So, take 1.6 and multiply it with 21. Which will give 3.2.

To go to the reverse of the above process you need to find power of 2 by which the floating point number will be divided to obtain the digit 1 before decimal point. After that use successive multiplications to change the fractional part to hexadecimal fraction. Proceed as follows:

  1. 3.2/21 = 1.6
  2. Take integral part from 1.6 to obtain the hex-digit 1 before decimal point.
  3. Multiply .6 by 16. The the integral part obtained will becomes a numeral in the hexadecimal fraction. Repeat this step with the obtained fractional part to the desired precision (6 is default).

    • .6 * 16 = 9.6 ---> Integral part = 9 Fractional part = .6
    • .6 * 16 = 9.6 ---> Integral part = 9 Fractional part = .6
    • .6 * 16 = 9.6 ---> Integral part = 9 Fractional part = .6
    • .6 * 16 = 9.6 ---> Integral part = 9 Fractional part = .6
    • .6 * 16 = 9.6 ---> Integral part = 9 Fractional part = .6
    • .6 * 16 = 9.6 ---> Integral part = 9 Fractional part = .6

So the hexadecimal fraction will become .999999 Now combine hex indicator 0x, hex-digit before decimal point and the hexadecimal fraction obtained along with exponent field to get the result.

3.210 = 0x1.999999p+116

Similarly you can obtain hexadecimal floating point number for numbers less than 1.0., for example 0.01. In this case to obtain the hex-digit 1 before decimal point you need to divide it with a number which is power of 2. Since 128 (25) after multiplying with 0.01 will give the number whose integral part becomes 1, 128*.01 = 1.28. It means you need to multiply 0.01 by 1/2-5 or you can say you need to divide it by 2-5 to get 1.28. Now apply the steps 2 and 3 stated above.

这篇关于如何在%printf语句转换工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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