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

时间:2015-03-02 05:02:03

标签: c ieee-754

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

Example using -3.14 as an example input

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

我已经有了双浮点和单浮点近似,但是我无法找到如何以IEEE 754表示法输出这些二进制数,并对它们进行颜色编码。任何关于如何做到这一点的想法/解决方案都将非常感激。

2 个答案:

答案 0 :(得分:4)

如果基础机器是深奥的,那么这并不能保证正确的答案:

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

答案 1 :(得分:2)

我决定借此机会重温我对IEE-754浮点标准的记忆。下面是我用于在其单精度浮点数表示中显示字符串的mashup,尽管它很容易被修改为双精度格式。

代码不适用于+ Inf,-Inf,NaN,尾随零,无分数和左外零(.fraction而不是0.fractioninteger.而不是{{ 1}})数字,它只是给出了如何以便携和明确定义(和高度娱乐)的方式做你想做的事情的一般概念。

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] = '\0';

    return TRUE; /* Success */
}

输出

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

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

更新:尽我所能

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

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

  • 修复零问题;

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

嗯,这很有趣!如果您在此(相当仓促的)代码中看到任何错误或改进空间,请发布它!