我正在编写一个C函数,该函数使我可以将任何float或double转换为包含32位0和1(根据IEEE754标准)的字符串。我不会使用printf,因为目标是了解它的工作方式并能够存储字符串。
我从以下视频中采用了微积分方法:https://www.youtube.com/watch?v=8afbTaA-gOQ。它使我能够将浮点数分解为符号的1位,指数的8位和尾数的23位。
我得到了一些不错的结果,但是我的转换器仍然不准确,尾数通常在最后几位是错误的。我用来计算尾数的方法是(其中strnew只是适当长度的malloc):
char *ft_double_decimals(double n, int len)
{
char *decimals;
int i;
if (!(decimals = ft_strnew(len)))
return (NULL);
i = 0;
while (i < len)
{
n = n * 2;
decimals[i++] = (n >= 1) ? '1' : '0';
n = n - (int)n;
}
return (decimals);
}
对于浮点数(例如0.1),我会得到以下尾数:1001 1001 1001 1001 1001 100我应该得到1001 1001 1001 1001 1001101。这真令人沮丧!我显然在这里丢失了一些东西,我想这与小数点的错误近似有关,所以如果有人知道我应该使用哪种方法而不是我正在使用的方法,我将不胜感激!
最佳答案
我的尾数在最后一点常常是错误的。
当转换不完全时,结果应四舍五入。 @Eric Postpischil
下面将中途情况舍入为零。
char *ft_double_decimals(double n, int len) {
char *decimals;
int i;
if (!(decimals = ft_strnew(len)))
return (NULL);
i = 0;
while (i < len) {
n = n * 2;
decimals[i++] = (n >= 1) ? '1' : '0';
n = n - (int) n;
}
// Add rounding code
if (n >= 0.5) {
int carry = 1;
while (i > 0) {
i--;
int sum = decimals[i] - '0' + carry;
decimals[i] = sum % 2 + '0';
carry = sum / 2;
}
if (i == 0 && carry > 0) {
// Rounding into the "one's" digit"
// TBD code to indicate to the caller that event
}
}
return (decimals);
}
int main(void) {
printf("%s\n", ft_double_decimals(0.1f, 23)); // --> 00011001100110011001101
return 0;
}
更常见的舍入:将中途情况舍入到最接近的偶数。
if (n >= 0.5 && (n > 0.5 || ((i > 0) && decimals[i-1] > '0'))) {
此外,当舍入结果为
"1.00000..."
时,需要通知调用代码关于c - 如何精确地将浮点数转换为二进制数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53555365/