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位表示。
这里写图片描述

关于浮点数的由十进制到二进制的转换大家一定也清楚,整数部分除二取余,小数部分乘二取整。
最后的结果是: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传入函数进行强转,其结果却差强人意。
(关于这点,目前还在测试,一定会有一个满意的解释的)

写到这里,差不多结束了,其实双精度浮点数的强转时类似,只要能完全掌握双精度浮点数在内存中的存数形式。

  • 19
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
好的,下面是一个基于状态机的词法分析器实现浮点数识别的示例代码: ```c #include <stdio.h> #include <ctype.h> #define STATE_INIT 0 #define STATE_INT 1 #define STATE_DOT 2 #define STATE_FRAC 3 #define STATE_END 4 int main() { char input[50]; int state = STATE_INIT; float num = 0.0f, frac = 0.1f; int i = 0; printf("请输入一个字符串:"); scanf("%s", input); while (input[i] != '\0') { switch (state) { case STATE_INIT: if (isdigit(input[i])) { num = input[i] - '0'; state = STATE_INT; } else { printf("不是浮点数\n"); return 0; } break; case STATE_INT: if (isdigit(input[i])) { num = num * 10.0f + (input[i] - '0'); } else if (input[i] == '.') { state = STATE_DOT; } else { state = STATE_END; } break; case STATE_DOT: if (isdigit(input[i])) { num += frac * (input[i] - '0'); frac *= 0.1f; state = STATE_FRAC; } else { printf("不是浮点数\n"); return 0; } break; case STATE_FRAC: if (isdigit(input[i])) { num += frac * (input[i] - '0'); frac *= 0.1f; } else { state = STATE_END; } break; default: break; } i++; } if (state == STATE_INT) { printf("%.0f\n", num); } else if (state == STATE_FRAC) { printf("%.2f\n", num); } else { printf("不是浮点数\n"); } return 0; } ``` 该代码通过一个状态机来实现浮点数的识别。状态机共有五个状态,分别是初始化状态(STATE_INIT)、整数部分状态(STATE_INT)、小数点状态(STATE_DOT)、小数部分状态(STATE_FRAC)和结束状态(STATE_END)。在每个状态下,根据不同的输入字符转换到不同的状态,并根据输入字符计算浮点数的值。最后根据状态输出相应的结果。注意,该代码没有考虑指数部分。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值