C/C++
type | len |
---|---|
bool | 1byte |
char | 1byte |
short | 1byte |
int | 4byte |
long | 4byte |
float | 4byte |
double | 8byte |
一个字节有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