C printf 浮点数舍入
C printf float rounding
我必须用 C
重新实现 printf(3)
,而不使用任何可以为我进行转换的函数。
我快完成了,我只需要 %a
,也快完成了,感谢你们:
男人说:
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.
所以我的问题是 rounded how ?
我发现:printf rounding behavior for doubles
它解释说 printf 正在使用 banker round 或 Round half to even 但我不知道如何实现它 我有试过这个:
a_double = round(a_double * pow(10, precision)) / pow(10, precision)
但是在 1000000
测试中,从 0.000001
开始并在每次失败 405201
次时添加 0.000001
,例如 0.000011
:
printf("%.6a", 0.000011) => 0x1.711948p-17
myprintf("%.6a", 0.000011) => 0x1.711947p-17
四舍五入'failed'和我没有得到和真正的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 比 7 更接近 8,所以我们输出“8”。这种魔法只对最后一个角色有效。对于非最后字符,始终使用整数部分,而根本不使用小数部分来确定输出哪个字符。然后,在此之后,我们输出 "p-17" 因为幂是 -17.
请注意,通常的舍入规则是将与 7 和 8 同样接近的 7.5 四舍五入为 8,而不是 7,而 6.5 将四舍五入为 7,而不是 6。但是,如果您想实施回合一半甚至你遇到例如。 6.5 然后向下舍入为 6,因为 6 是偶数而 7 不是。我不确定您发现的有关庄家回合的内容是否也适用于 %a,您唯一可以做的就是测试实施各种舍入算法并查看哪个结果与 printf 的真实 %a 相同。不应该那么难,因为不同的舍入算法只是在处理一半的方式上有所不同。其余四舍五入到最接近的数字。
顺便说一句,我在你之前的问题 () 中说错了,因为 3.2 具有非舍入表示 1.999999....p+1 和舍入表示 1.99999ap+ 1 由于浮点精度有限,最后一个 "a" 会出现。当然,它是由于四舍五入而不是由于有限的浮点精度而发生的,正如您现在可能已经意识到的那样。
我必须用 C
重新实现 printf(3)
,而不使用任何可以为我进行转换的函数。
我快完成了,我只需要 %a
,也快完成了,感谢你们:
男人说:
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.
所以我的问题是 rounded how ?
我发现:printf rounding behavior for doubles
它解释说 printf 正在使用 banker round 或 Round half to even 但我不知道如何实现它 我有试过这个:
a_double = round(a_double * pow(10, precision)) / pow(10, precision)
但是在 1000000
测试中,从 0.000001
开始并在每次失败 405201
次时添加 0.000001
,例如 0.000011
:
printf("%.6a", 0.000011) => 0x1.711948p-17
myprintf("%.6a", 0.000011) => 0x1.711947p-17
四舍五入'failed'和我没有得到和真正的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 比 7 更接近 8,所以我们输出“8”。这种魔法只对最后一个角色有效。对于非最后字符,始终使用整数部分,而根本不使用小数部分来确定输出哪个字符。然后,在此之后,我们输出 "p-17" 因为幂是 -17.
请注意,通常的舍入规则是将与 7 和 8 同样接近的 7.5 四舍五入为 8,而不是 7,而 6.5 将四舍五入为 7,而不是 6。但是,如果您想实施回合一半甚至你遇到例如。 6.5 然后向下舍入为 6,因为 6 是偶数而 7 不是。我不确定您发现的有关庄家回合的内容是否也适用于 %a,您唯一可以做的就是测试实施各种舍入算法并查看哪个结果与 printf 的真实 %a 相同。不应该那么难,因为不同的舍入算法只是在处理一半的方式上有所不同。其余四舍五入到最接近的数字。
顺便说一句,我在你之前的问题 (