我正在编写一个 C 函数,它允许我将任何 float 或 double 转换为包含 32 位 0 和 1 的字符串(根据 IEEE754 标准)。我不会使用 printf,因为目的是了解它的工作方式并能够存储字符串。
我从这个视频中获取了微积分方法:https://www.youtube.com/watch?v=8afbTaA-gOQ 。它使我能够将 float 解构为 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 这样的 float ,我得到这个尾数:1001 1001 1001 1001 1001 100,我应该得到 1001 1001 1001 1001 1001 101。这太令人沮丧了!我显然在这里遗漏了一些东西,我想这与小数的错误近似有关,所以如果有人知道我应该使用什么方法而不是我正在使用的方法,我将非常感激! p>
最佳答案
my mantissa is often wrong in the last bits.
当转换不完整时,结果应四舍五入。 @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 - 如何精确地将 float 转换为二进制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53555365/