在 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.fraction
或 integer.
而不是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 它!
我目前正在开发一个需要这种输出的程序:
我必须在 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.fraction
或 integer.
而不是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 它!