在 C 中将 32 位和 64 位数字转换为 IEEE 754 二进制

Converting 32-bit and 64-bit numbers to IEEE 754 binary in C

我目前正在开发一个需要这种输出的程序:

我必须在 C 中输出 64 位和 32 位数字的 IEEE 754 二进制文件。

我已经有了双浮点数和单浮点数近似值,但我无法找到如何以 IEEE 754 表示法输出它们的二进制,以及如何对它们进行颜色编码。任何关于如何做到这一点的 thoughts/solutions 将不胜感激。

如果底层机器是深奥的东西,这不能保证正确答案,但是:

float f = 3.14;
uint32_t u;
memcpy(&u, &f, sizeof u);
for (int i = 31; i >= 0; i--)
  putchar('0' + ((u >> i) & 1));

我决定借此机会重温一下我对IEE-754浮点标准的记忆。下面是我为以单精度浮点数表示形式显示字符串而制作的混搭,尽管它很容易修改为双精度格式。

该代码不适用于 +Inf、-Inf、NaN、尾随零、无小数和遗漏零(.fraction 而不是 0.fractioninteger. 而不是integer.0) 数字,它只是应该给出如何以可移植且定义明确(且非常有趣)的方式做您想做的事情的一般概念。

#define EXPLEN 8 /* Fraction length for single-precision */
#define SIGNIFLEN 23 /* Significand length for single-precision */
#define EXPBIAS 0x7F /* Exponent bias for single-precision */
#define BITLEN (1 + EXPLEN + SIGNIFLEN)

BOOL strToFloat(char *floatStr, char *outBits, size_t outBitsLen){
    unsigned long int floatStrLength = strlen(floatStr), intPart, fracPart, intPartHighestBit = 1, fracPartLength,
        fracPartPowTen = 1, temp;
    char roundBit, stickyBit, expPart = 0;
    int i;

    /* Get sign */
    if (floatStr[0] == '-'){
        floatStr++;
        outBits[0] = '1';
    } else {
        if (floatStr[0] == '+')
            floatStr++;
        outBits[0] = '0';
    }

    if (sscanf(floatStr, "%lu.%lu", &intPart, &fracPart) == EOF ||
        outBitsLen < BITLEN + 1)
        return FALSE; /* Failure */

    /* Get integer part */
    temp = intPart;
    while (temp >>= 1)
        intPartHighestBit <<= 1;

    for (i = EXPLEN + 1; i < BITLEN && (intPartHighestBit >>= 1); i++, expPart++)
        outBits[i] = !!(intPart & intPartHighestBit) + '0';

    /* Get fraction part */
    fracPartLength = strlen(strchr(floatStr, '.'));
    while (--fracPartLength)
        fracPartPowTen *= 10;

    if (!intPart && i == EXPLEN + 1)
        if (fracPart > 0){
            i--;
            expPart--;
        } else
            expPart = -EXPBIAS;

    for (; i < BITLEN; fracPart = (fracPart << 1) % fracPartPowTen){
        outBits[i] = !!((fracPart << 1) - (fracPart << 1) % fracPartPowTen) + '0';

        if (outBits[i] == '0' && i == EXPLEN) /* Start writing only after first set bit is reached if number <1 */
            expPart--;
        else
            i++;
    }

    /* Get exponent part */
    for (i = EXPLEN, expPart += EXPBIAS; i > 0; i--, expPart >>= 1)
        outBits[i] = (unsigned char)expPart % 2 + '0';

    /* Round fraction part (to-nearest mode) */
    if ((fracPart << 1) - (fracPart << 1) % fracPartPowTen){ /* Guard bit set, rounding needed */
        fracPart = (fracPart << 1) % fracPartPowTen;

        roundBit = !!((fracPart << 1) - (fracPart << 1) % fracPartPowTen);
        fracPart = (fracPart << 1) % fracPartPowTen;

        stickyBit = !!((fracPart << 1) - (fracPart << 1) % fracPartPowTen);

        if (roundBit || stickyBit || outBits[BITLEN - 1] == '0'){ /* Round up, add 1 to mantissa (and to exponent
                    if mantissa overflows)*/
            for (i = BITLEN - 1; outBits[i] == '1' && i > 0; i--)
                outBits[i] = '0';
            outBits[i] = '1';
        }
    }

    outBits[BITLEN] = '[=10=]';

    return TRUE; /* Success */
}

用法示例:

char *str = "-3.14",
    *outFloat = malloc(BITLEN + 1);

if (outFloat && strToFloat(str, outFloat, BITLEN + 1))
    printf("%s", outFloat);

产出

11000000010010001111010111000011

更新:尽我所能

  • 删除幻数,以便更容易将其更改为使用双精度格式;

  • 修复(我认为)舍入溢出;

  • 修复归零问题;

  • 重构设置符号位的代码;而且我还根据 @Segmented 在评论中的要求摆弄了一些类型。

嗯,那很有趣!如果您发现任何错误或 space 需要改进此(相当仓促的)代码,请 post 它!