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

我快完成了,我只需要%a,也快完成了,谢谢你们:How %a conversion work in printf statement?

那人说:


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


那么我的问题是如何四舍五入的呢?

我发现:printf rounding behavior for doubles

它说明了printf正在使用banker round或Round half来达到偶数,但是我不知道如何实现它,我已经尝试过了:

a_double = round(a_double * pow(10, precision)) / pow(10, precision)


但是在1000000测试中,从0.000001开始并在每次失败0.000001次(例如,使用405201)时添加0.000011

printf("%.6a", 0.000011) => 0x1.711948p-17
myprintf("%.6a", 0.000011) => 0x1.711947p-17


四舍五入“失败”,我没有得到与真实printf相同的值。

我不认为将double转换为hexa notation的算法是错误的,因为精度为13的我绝对没有错误。

因此,我只想知道如何在printf上进行与double相同的舍入。

最佳答案

好的,所以我想我以前的算法没有完全实现舍入,所以让我们看一下如何将结果舍入。我也将您的示例编号用作我的示例编号。首先,我们发现0.000011 /(2 ^(-17))= 0.000011 *(2 ^ 17)= 1.441792,因此功效为-17。然后,我们输出“ 1”,从1.441792中减去1,然后乘以16,得到7.068672。我们输出7,减去7,然后乘以16,得到1.09875199999999。我们输出1,从中减去1,然后乘以16,得出1.58003199999985。我们输出1,从中减去1,然后乘以16,得到9.28051199999754。然后输出9,减去9,再乘以16,结果为4.48819199996069。我们输出4,减去4,再乘以16,结果是7.81107199937105。

现在,我们将输出最后一个字符。现在我们做魔术。因为7.81107199937105比8更接近于8,所以我们输出“ 8”。此魔术仅适用于最后一个角色。对于非最后一个字符,在确定要输出哪个字符时,始终使用整数部分,而根本不使用小数部分。然后,在此之后,因为功率为-17,所以我们输出“ p-17”。

请注意,通常的舍入规则说,将与7和8均相等的7.5舍入为8,而不是7和6.5会舍入为7,而不是6。但是,如果要实现舍入一半为偶数而你遇到例如6.5然后将其舍入为6,因为6是偶数,而7不是。我不确定您对银行家回合的发现是否也适用于%a,您唯一能做的就是测试实现各种舍入算法,然后看看给出的结果与printf的真实%a相同。不应该那么难,因为不同的舍入算法只是在处理一半方面有所不同。其余的四舍五入到最接近的数字。

顺便说一句,我在您先前的问题(How %a conversion work in printf statement?)中说的是错误的:对于具有非舍入表示形式1.999999 .... p + 1和舍入表示形式1.99999ap + 1的3.2,最后一个“ a”将由于有限的浮点精度而发生。当然,它的发生是由于舍入而不是由于浮点精度的限制,正如您可能已经意识到的那样。

10-04 14:54
查看更多