本文只考虑了IEEE规格化值的转换场景,非规格化值/无穷大/NaN 等情况未做考虑。
关于浮点数的表示,推荐阅读《CSAPP》第二章:信息的表示和处理。
=================
虽然C语言自带隐式类型转换,即:
float f=12.25;
int a=f;
printf("%d\n",a); //结果是12
但是这几天了解了float的结构,所以自己写了一个函数 int ftoi(const float f) 来实现它
下面是float的结构:
float一共32位,其结构定义如下:
|-------- 31 -------|------------ 30-23 ------------ |------------ 22-0 ------------|
符号位(sign) 指数部分(exp) 小数部分(mag)
sign:符号位就一位,0表示正数,1表示负数
exp: 指数部分长8位,无符号整数。
阶码 E=exp-Bias,阶码长度k=8的情况下,Bias=2^(8-1) - 1 = 127。
mag:小数部分,定点小数,小数点在最左边,隐含了一个小数点左侧的1。
小数M = 1 + mag。
整体上是以2进制的科学记数法来表达,即:
V = 2^E * M
那么要将整数位求出来,就必须分别提取出sign,exp,mag 三部分的二进制代码,所以使用位运算达成目标。
#include<stdio.h>
int ftoi(const float f);
int ftoi(const float f){
int i=0,mid_num,k,f_mag=0,f_exp=0,f_sign=0;
mid_num=*(int *)&f;
if( mid_num>>31){ //求出符号位为1还是为0
f_sign = 1;
}
f_exp = mid_num & 0x7f800000; //求出指数大小
f_exp = f_exp >> 23;
f_exp = f_exp - 127;
if( f_exp > 0 ){ //如果指数大于0则如下处理
i=1<<f_exp; //因为是科学计数表示法,尾数部分只有小数位,所以得自己加上1*2^f_exp
f_mag=mid_num & 0x7fffff; //提出尾数部分
while(--f_exp>=0){ //从尾数中取出原来的整数位的数字
f_mag=f_mag<<1;
k=(( (f_mag&0x800000) != 0 )?1:0);
i+=k<<f_exp;
}
if(f_sign==1) //若原f是负数,则返回负整数值
i=-i;
}
if(f_exp == 0){
i=1; //若指数为0,则根据 f_sign 返回1或-1
if(f_sign==1)
i=-1;
}
return i;
}
int main(int argc,char *argv[]){
float f;
int i;
scanf("%f",&f);
i=ftoi(f);
printf("ftoi(f)=%d\n",i);
return 0;
}
关于非规格化数 / 无穷大 / NaN 等含义,建议参考csapp上的描述。