【发布时间】:2012-06-10 08:17:41
【问题描述】:
我想弄清楚如何在不使用库函数的情况下打印浮点数。打印浮点数的小数部分非常容易。打印整体部分更难:
static const int base = 2;
static const char hex[] = "0123456789abcdef";
void print_integral_part(float value)
{
assert(value >= 0);
char a[129]; // worst case is 128 digits for base 2 plus NUL
char * p = a + 128;
*p = 0;
do
{
int digit = fmod(value, base);
value /= base;
assert(p > a);
*--p = hex[digit];
} while (value >= 1);
printf("%s", p);
}
打印FLT_MAX 的组成部分可以完美地与base 2 和base 16 配合使用:
11111111111111111111111100000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000 (base 2)
ffffff00000000000000000000000000 (base 16)
但是,以 10 为基数打印会导致前 7 位数字之后出现错误:
340282368002860660002286082464244022240 (my own function)
340282346638528859811704183484516925440 (printf)
我假设这是除以 10 的结果。如果我使用双精度而不是浮点数会更好:
340282346638528986604286022844204804240 (my own function)
340282346638528859811704183484516925440 (printf)
(如果您不相信printf,请在 Wolfram Alpha 中输入2^128-2^104。这是正确的。)
现在,printf 如何打印出正确的结果?它是否在内部使用了一些 bigint 设施?还是我缺少一些浮点技巧?
【问题讨论】:
-
你为什么不看看一些
printf()的实现? -
@wilx 我不想作弊 ;)
-
很难准确有效地打印浮点值,除非基数是 2 的幂(对于二进制浮点,基数是 2 的幂和十进制浮点数的 5 的乘积)点表示)。在基数为 10 的情况下,如果使用大整数 (
m*2^(-p) == (m*5^p)*10^(-p)),它会变得相当容易。在不使用大整数的情况下,您可以首先获取二进制表示并将其转换为十进制,整数部分使用double dabble,小数部分使用类似的东西。但这不是很有效。 -
你可能会发现我关于这个主题的文章很有趣——从这里开始:exploringbinary.com/…
-
标签: c string floating-point floating-accuracy