1. 问题和别人的工作
IEEE754是浮点数在计算机中存储的技术规范。在学习手动计算 科学计数法/小数形式 与 二进制/十六进制 相互转换的过程中,我们可以使用IEEE754浮点数计算器帮助检验计算结果。
网上不少有在线的IEEE754浮点数计算器,都能符合要求1.你给出小数形式,计算器算出二进制;2.你给出二进制,计算机器算出小数形式。
比如
https://www.h-schmidt.net/FloatConverter/IEEE754.html
界面长这样。
再如
http://www.binary-calculator.com/
界面长这样。
如果没有网怎么办?这里给出一个C语言版的。
2. hex2float,我给出二进制,计算器求浮点数
偷了两个懒。第一,既然二进制和十六进制转换非常简单,是程序员的基本功,因此就不实现了。我给出的不是二进制格式,而是十六进制,如0x12345678。以下,不对二进制和十六进制作区分。第二,不从控制台或者命令行参数,而是硬编码,在代码中给变量赋值。这两点都不是技术难点。
代码如下。
#include <cstdio>
#include <cstdlib>
int main()
{
float f = 1;
*(unsigned int*)&f = 0x12345678;
printf("%x\n",*(unsigned int*)&f);
printf("%e\n",f);
return(0);
}
运行的结果是这样的:
>hex2float.exe
0x12345678
5.690457e-28
即,你手动把二进制0x12345678转换成浮点数,如果结果是5.690457e-28,那么就做对了。
涉及到的核心技巧,*(unsigned int*)&f = 0x12345678; 是把 float 型变量f 取地址得到指针,再转换指针基类型为(unsigned int*),最后去地址引用再赋值。
交叉检验一下。
二进制0x12345678对应的IEEE754浮点数在
https://www.h-schmidt.net/FloatConverter/IEEE754.html
可以得到,如下图所示。是5.690457e-28附近没错。
如果需要计算别的二进制,把代码中的0x12345678改成想求的数就行了。
3. float2hex,我给出浮点数,计算器求二进制
代码如下。
#include <cstdio>
#include <cstdlib>
int main()
{
float f = 5.6904566139e-28; //0x12345678
int a = *(unsigned int*)&f;
//a = 0x12345678;
printf("%x %x %x %x\n",a%0x100, a/0x100%0x100, a/0x10000%0x100, a/0x1000000);
FILE *fp;
fp = fopen( "file.bin" , "w" );
fwrite(&f, sizeof(char) , 4, fp );
fclose(fp);
return(0);
}
核心技巧是 int a = *(unsigned int*)&f; 这一行,把等号右边的(float型变量通过指针得到的)整型变量的值取出来。下一行,是标准的计算机等级考试二级题目思路,通过取整和求余操作,得到整数切成十六进制每2位一段。
运行结果如下。
>float2hex
78 56 34 12
为什么这么“颠倒”排列显示呢?明明代码里是先低权重后高权重的。我们可以把这4个字节作为4个char写到磁盘文件中对比一下。
用十六进制工具查看file.bin的内容,如下。
也是颠倒存放的。输出到控制台的写法,是为了与内存中的存放次序,也即磁盘文件的存放次序保持一致。之所以在内存中顺序如此,是因为我的计算机是Intel系列CPU,小端模式。为什么向控制台输出看起来像大端,所以还需要特意颠倒输出顺序呢?因为那是整数,不是内存映射,低字节 vs. 高字节,而是 低权重 vs. 高权重,且与地址无关。
IEEE754并不遥远,一点也不陌生,就在常见的C语言的代码之中,一直就在我们身边,只是我们不一定看得到。