我需要为一个项目重做printf
,所以我实际上在float
的转换上遇到了问题。
我成功地转换了几乎所有内容,但数字 1254451555.6
我遇到了一个问题:我收到 1254451555.59999
。
我认为保留 .
之后的部分的计算不起作用。
nbr = ((n - nbr) * 100000000);
我尝试了不同的方法,但还没有成功解决它。
你有什么想法吗?
int getlenghtitoa(long long n, int nbase)
{
int i;
i = 0;
while (n >= 0)
{
n /= nbase;
i++;
if (n == 0)
break ;
}
return (i);
}
float ft_nbconv(float n, int i)
{
while (i-- > 0)
n = n *10;
return (n);
}
int ft_power(long long nbr)
{
int i;
i = 1;
while(nbr > 10)
{
i *= 10;
nbr = nbr / 10;
}
return (i);
}
char *ft_conver_f(long double n)
{
char *dest;
int i;
int a;
long long int nbr;
int power;
nbr = (long long) n;
i = getlenghtitoa((long long )n, 10);
if (!(dest = malloc(sizeof(char) * (i + 8))))
return (0);
a = i;
i = 0;
power = ft_power(nbr);
while (a--)
{
dest[i++] = ((nbr / power) % 10) + '0';
if (power != 1)
power /= 10;
}
dest[i++] = '.';
nbr = ((n - nbr) * 100000000);
power = 10000000;
while (a++ < 5)
{
if (a == 5)
if ((((nbr / power)) % 10) >= 5)
{
dest[i++] = ((nbr / power) % 10 + 1) + '0';
break;
}
dest[i++] = ((nbr / power) % 10) + '0';
power /= 10;
}
dest[i] = '\0';
return (dest);
}
最佳答案
大多数十进制分数不能精确地表示为二进制分数。其结果是,一般情况下,您输入的十进制 float 只是机器中实际存储的二进制 float 的近似值。
这就是为什么在实现 printf 时,真正能够将 float 转换为 2 位分隔整数的唯一方法是使用精度因子并手动舍入。 如果不需要实现精度,则默认为 6。 (精度是点后要打印的位数(并且是四舍五入的))。 这就是您的实现中所缺少的。 我们将点之前的数字称为 ipart ,将点之后的数字称为 fpart 。
nbr = ((n - nbr) * 100000000);
这应该是
nbr = ((n - nbr) * 10000000); // 7 zeros
// nbr is now equal to 5999999
if (nbr % 10 >= 5)
{
nbr = nbr / 10 + 1;
}
else
nbr = nbr / 10;
这样,你就得到了点后的7位数字,看看最后一位是否大于5,如果是,你在nbr上加上+1(除以10后确保nbr有 6 位数字),如果不是,则除以 10。
关于此舍入方法的另一个注意点是,它将无法将 fpart 舍入到 ipart 。 如果你想打印 3.9999999 该怎么办?它应该打印 4.000000。这意味着不能只是从头开始将 ipart 转换为字符串,因为有时舍入 fpart 会将 +1 添加到您的 ipart
因此,考虑创建一个函数ltoa,例如,它需要一个 long long int 并将其转换为字符串,完成我刚刚给您的关于舍入的代码段,以确保可以进行舍入到 ipart ,然后使用类似的东西将整个内容转换为字符串
dest = join(ltoa(ipart), ".", ltoa(fpart)).
还有一些注意事项,您的函数不处理负数。 而且你的int ft_pow很容易被淹没,所以考虑改为long long ft_pow
关于在c中将十进制数转换为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58679722/