C语⾔实现浮点数的整型强制转化
1.整型在内存中的存储形式
int 与 float 均是四个字节⼤⼩,即32位,但是他们在内存中的存储形式却是完全不相同的。
下⾯举⼀个例⼦,在vs下通过查看内存验证⼀下以上的事实。
1.1 int a = 12;
由于是正数,所以符号位取0。
(12) = 1010B
所以其在内存中存储形式为 0101 0000 0000 0000 0000 0000 0000 0000
为了⽅便计算16进制数,将4位⼆进制数列为⼀组进⾏表⽰。
在监视窗⼝到a的地址。
通过地址查看该地址存储的信息。
将其展开 0000 1010 0000 0000 0000 0000 0000 0000
2.单精度浮点数在内存在内存的储存
举例 float b = 12.125;
在监视窗⼝到b的地址
通过b的地址,查看⼀下b在内存中的存储形式。
可见,b在内存中4字节是按照 00 00 42 41存储,因为我的机器是⼩端模式,所以真正的存储形式是 41 42 00 00。接下来分析⼀下这32个位都是什么,⼤家都知道⼆进制的四位可以⽤⼗六进制的1位表⽰。
浮点型变量float关于浮点数的由⼗进制到⼆进制的转换⼤家⼀定也清楚,整数部分除⼆取余,⼩数部分乘⼆取整。
最后的结果是:12.125(10) = 1100.001(2)
浮点数共计占内存4个字节,即32位。这32位是按照这样的规则存储的:
(1)⼀位符号位 整数为0 负数1。⽤0,1将符号数字化,因为计算机是不懂正负号,⽽0和1恰恰可以表⽰这两种状态。
(2)指数位⼋位
⽐如 float a = 12.125(10) = 1100.001(2)
其实就是科学计数法表⽰, 1.2125 * 10^1 (10) = 1.1100001 * 2^3
所在其指数位就为 exp = 3,但是实际计算机在存储的过程中还给指数位加了⼀个偏移常数127,所以指数为最终的结果是130。以⼆进制表⽰就是1000 0010。
(3)由⼆步骤可以知道12.125尾数为1.1100001,但是可以联想⼀下,任意⼀个单精度类型的数据转化成科学计数法的⼆进制数都是1.xxxxxxxxxx,因此实际上在存储中将第⼀位的略去不表⽰,这样⼀来。其实在尾数位,我们⽤23位保存了24的数据,这样进度就提⾼了⼀位。
由上图可知,这样的事实成功的被验证了。
洋洋洒洒,废话连篇。真正转化现在开始,了解了前⾯的知识,我们就知道了浮点数是如何计算机中存储的,将其转换成整型⽆⾮就是取到它的整数部分即可。
下⾯实现这样的⼀个单精度浮点数到整型的强转函数:
int float_to_int(float f)
{
int *p = (int*)&f;
//由于指针访问内存是按照基类型进⾏的,⾸先进⾏强转访问浮点数f
int temp = *p;
//⽤中间变量接受f的值
//提取符号位
int sign = -1;
if((temp & 0x80000000) == 0)
{
sign = 1;
}
//条件表达式中进⾏了位与运算,其实就是提取指数位的值。前⾯已经讲过了,符号位为0,其为正值。若为1,其为负值。
//提取指数位
int exp;
exp = ( ( (temp >> 23) & 0x0ff ) ) - 127;
//由于在存储的时候指数位加了偏置常数现在相当于是计算指数位的逆过程所以⾃然要减去
//提取尾数位
int tail;
tail = ( ( temp & 0x007fffff ) | 0x00800000 );
/*和之前提取指数位和符号位的⽅法是⼀致的,要提取哪⼏位,在对应的位进⾏与1运算就可以了
现在我们要提取的是除符号位和指数位共计九位的其他23,即尾数为。只需要在对应的为与1即可*/
/*还记得在存储尾数的时候,因为任意⼀个单精度的⼆进制数以科学记数法表⽰时,第⼀位都是1,
所以存储的时间,为了能够提⾼精度,省略了改位。但是现在是在进⾏他的逆过程,所以我们要在
要进⾏或1位运算*/
int res = (tail >> (23 - exp));
return res * sign;
}
//进⾏验证
int main()
{
float a = 12.125; //a = -12.125 a = 0.05 a = -0.05
int b = float_to_int(a);
printf("b = %d\n",b);
}
⼤家也可⾃⾏验证,但是美中不⾜的是这样强转函数存在缺点,就是当我们将浮点数0传⼊函数进⾏强转,其结果却差强⼈意。 (关于这点,⽬前还在测试,⼀定会有⼀个满意的解释的)
写到这⾥,差不多结束了,其实双精度浮点数的强转时类似,只要能完全掌握双精度浮点数在内存中的存数形式。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论