浮点型的内存表示级数据类型转化


C/C++

typelen
bool1byte
char1byte
short1byte
int4byte
long4byte
float4byte
double8byte

一个字节有8位 28=256

二进制如何表示负数

整数7用二进制表示为
0000 0111
+ ?
||
0000 0000
为了简单的使7 + (-7) = 0, -7 二进制表示为 1111 1001。也就是我们经常说的负数的二进制表示为正数的反码加1。

推导过程
0000 0000 0000 1111 (15)
1111 1111 1111 0000 (15的反码)
1111 1111 1111 1111 (加上1就可以导致数据溢出,8位清零)
0000 0000 0000 0001 (-15 表示为 1111 1111 1111 0001)
0000 0000 0000 0000 (0)

浮点数如何计算

ANSI/IEEEStd 754-1985标准

IEEE 754是最广泛使用的二进制浮点数算术标准,被许多CPU与浮点运算器所采用。IEEE754规定了多种表示浮点数值的方式,在本文档里只介绍32bits的float浮点类型。它被分为3个部分,分别是符号位S(sign bit)、指数偏差E(exponent bias)和小数部分F(fraction)。

在这里插入图片描述

其中S位占1bit,为bit31。S位为0代表浮点数是正数,S位为1代表浮点数是负数,比如说0x449A522C的S位为0,表示这是一个正数,0x849A522C的S位为1,表示这是一个负数。
E位占8bits,为bit23~bit30。E位代表2的N次方,但需要减去127,比如说E位为87,那么E位的值为2(87-127)=9.094947017729282379150390625e-13

F位占23bits,为bit0-bit22。F位是小数点后面的位数,其中bit22是2-1=0.5,bit21是2-2=0.25,以此类推,bit0为2-23=0.00000011920928955078125。但F位里隐藏了一个1,也就是说F位所表示的值是1+(F位bit22~bit0所表示的数值),比如说F位是0b10100000000000000000001,只有bit22、bit20和bit0为1,那么F位的值为1+(2-1+2-3+2-23),为1.62500011920928955078125。

综上所述,从二进制数换算到浮点数的公式为:(-1)S×2E-127×1.F

举个换算的例子:
下面来看看浮点数与二进制数如何转换。

二进制数换算成浮点数:

假如在内存中有一个二进制数为0x449A522C,先将十六进制转换成二进制,如下:
0100 0100 1001 1010 0101 0010 0010 1100

按照SEF的格式分段,如下:

0 10001001 00110100101001000101100

这个数值不是特殊的情形,可以按照公式(-1)S×2(E-127)×(1+F)转换。S位的值为(-1)0=1,E位的值为2137-127=1024。F位的值为1+2-3+2-4+2-6+2-9+2-11+2-14+2-18+2-20+2-21= 1.205632686614990234375。最终结果为1×1024×1.205632686614990234375=1234.56787109375。

其中F位比较长,使用二进制方式转换比较麻烦,也可以先转换成十六进制再计算,转换为十六进制如下:

0011 0100 1010 0100 0101 1000

0x3 0x4 0xA 0x4 0x5 0x8

F位为23bits,需要在最后补一个0凑成24bits,共6个十六进制数。F位的值为1+3×16-1+4×16-2+10×16-3+4×16-4+5×16-5+8×16-6=1.205632686614990234375,与上面使用二进制方法得到的结果相同。

数据类型转化

字符转化为short

 char ch = 'A';
 short S = ch;
 printf("S is %d\n", S);

程序打印结果:

S is 65

从内存的角度分析,char型数据占一个字节,short占两个字节,把ch 赋值给S,ch的8位复制到S低8位,S的高8位为0,表示为 0000 0000 0100 0001。

short型转化为char型

short sh = 512;
char ch1 = sh;
printf("ch1 = %d\n", ch1);

程序打印结果为:

ch1 = 0

从内存角度分析,short占2个字节 也就是16byte,0010 0000 0000,char占一个字节8byte, 将short型的sh赋值给char型ch1,实际上赋值的是sh的低8位 0000 0000。所以ch1 的打印结果为0。

int型转化为short

int t = 1782579;
short s1 = i;
printf("s1 = %d\n", s1);

程序运行结果:

s1 = 2097

从内存的角度分析,int型的i赋值给short型的s1,实际上是将t的低16位复制给s1。

负数赋值

 41     short ss = -1;
 42     int ii = ss;
 43     printf("ii = %d\n", ii);

程序运行结果:

ii = -1

从内存角度分析,ss 为1111 1111 1111 1111,将ss 赋值给ii,将16位复制到ii的低16位,然后进行符号扩展, ii 为 1111 1111 1111 1111 1111 1111 1111 1111。

int 型转化为float

 45     int a = 5;
 46     float f = a;
 47     printf("f = %f \n", f);

程序运行结果:

f = 5.000000

为什么是5.0, 实际上int 5被翻译成1.25 * 22, 套用公式“(-1)s * 1.xxxx * 2exp-127”可以得出 s=0,xxxx=0.25, exp = 129, 根据这些值可以画出float f的内存结构图 0 1000 0001 0100 000 …0 。

再看一个例子:

 49     int b = 37;
 50     float c = *(float *)&b;
 51     printf("c = %f\n", c);

程序运行结果:

c = 0.000000

为什么会是0呢?操作系统将指向(int *)的地址认为是指向(float * ),所以对于b所指向的四个字节的空间会按float类型翻译,32 刚好位于 F区域,翻译成float型数据会是一个很小的数据。

 53     float d = 7.0;
 54     short e = *(short *)&d;
 55     printf("e = %hd\n", e);

程序运行结果:

e = 0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值