__c语言__整型、实型的存储(十进制转二进制)
float 和 double 类型数据在内存中的存储方法
- 无符号整型采用32位编码,带符号整型数采用1个符号位31位底数编码;
- 单精度数据采用了1位符号位,8位阶码,23位尾数的编码;
- 双精度数据采用了1位符号位,10位阶码,52位尾数的编码;
- 无符号整型的范围:0~2的32次方
- 带符号整型:-2的31次方~2的31次方
- 单精度规定用 8 位二进制表示阶数,即最大表示为 2 的 128 次方,把这个数算出来是 3.4028236692093846346337460743177e+38
- 双精度规定用 11 位二进制表示阶数,即最大表示为 2 的 1024 次方,结果是 1.797693134862315907729305190789e+308
- 浮点数(单精度的 float 和双精度的 double)在内存中以二进制的科学计数法表示,表达式为 N = 2^E * F;
其中E为阶码(采用移位存储),F 为尾数。
- float 和 double 都由符号位、阶码、尾数三部分组成,float 存储时使用 4 个字节,double 存储时使用 8 个字节。
各部分占用位宽如下所示:
符号位 阶码 尾数 长度
float 1 8 23 32
double 1 11 52 64
符号位:0代表正数,1代表负数。
阶码:用移位表示法存储科学计数法中的指数数据
float阶码占8位,取值范围-128~127,但并没有按照移位表示法+128,而是+127。
同理double要+1023。阶码也是指数位
尾数:用二进制的科学计数法表示后,去掉小数点前面恒定的1,只保留小数点后面的二进制数据,存入尾数位置即可。
- 比如8.25,二进制科学计数法表示为:1.00001*2^3,
具体转换方法:
8的二进制1000;
.25的二进制.01:即0*2^(-1) + 1*2^(-2)。
写为:1000.01,小数点左移3位,即转换完毕。
符号位确定:8.25为正数,符号位为0。
阶码的表示:阶码位3+127=130;二进制10000010,已经是8位。
尾数的表示:去掉小数点前面的1,为00001,后面补充0至23位:000 0100 0000 0000 0000 0000
最终8.25在内存里存储的二进制为:0100 0001 0000 0100 0000 0000 0000 0000
- 又比如11.4,二进制科学计数法表示:
float:1.01101100110011001100110 * 2^3
double:1.0110 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 * 2^3
所以他们的值其实是不同的,因为.4用二进制无法精确表示
——这也就是为什么 float 类型数据 和 double 类型数据 都存储11.4,但是对比起来,他们不相等的原因。
比如 float a = 11.4; double b = 11.4; 要让他们正确对比,((float)b == a),让 double 数据舍弃比 float 多的那些尾数。
- 对于 double 型数据,只要将阶码前面加0扩展到11位,尾数后面补充0至52位即可。
移位表示法:
在数 X 上加一个偏移量,常用于表示浮点数中的阶码(注意阶码的偏移量和移位表示法定义有差别)。
定义:
若 X为纯整数,X[移] = 2^(n-1) + X,-2^(n-1) <= X < 2^(n-1);
若X为纯小数,X[移] = 1 - X,-1<= X < 1
下面这个代码,我很喜欢,其中有很多思想,对我来说很有用,膜拜下某大神
#include <stdio.h> #define print_float(a) print_bitxx(a, 4) #define print_int(a) print_bitxx(a, 4) #define print_double(a) print_bitxx(a, 8) int is_little_endian() { short int x = 0x0001; return ((char*)&x)[0]; } void print_bitxx(const void *a, int bytes) { const unsigned char *pos = (const unsigned char *)a; int i, j; int max_i; max_i = bytes - 1; if(is_little_endian()) { for(i=max_i; i>=0; i--) { for(j=7; j>=0; j--) { printf("%d", ((pos[i] & (1 << j)) ? 1 : 0)); if (j == 4 || j == 0) printf(" "); } printf(" "); } } printf("\n"); } int main(int argc, char **argv) { int a = 8.25; float b = 8.25; double c = 8.25; print_int(&a); print_float(&b); print_double(&c); printf("%d\n", b == (float) c); printf("%d\n", (double)b == (double) c); return 0; }
然后就是我的学习时间了
1、编写程序把一个整型二进制数中 1 的个数,最高位1的位置和最低位1的位置显示出来。
程序接受用户输入的一个整数(分别正数一个,负数一个)
输出该整数,以及其中 1 的个数,最高位 1 的位置,最低位 1 的位置。
用GCC编译程序运行,检查程序运行是否正确。
/*编写程序 把一个整型二进制数中1的个数,最高位1的位置和最低位1的位置显示出来。 程序接受用户输入的一个整数(分别正数一个,负数一个), 输出该整数, 以及其中1的个数, 最高位1的位置, 最低位1的位置。 一个示例的输出如下 NUMBER: 2049 BITS: 2 HIGHEST 1: 11 LOWEST 1: 0 据实验:输入的数字范围是(-2^31) 到 (2^31 - 1) -2147483648 到 2147483647 本代码移位运算测试,int 和unsigned int无区别 */ #include <stdio.h> int main(int argc , char *argv[]) { int num = 0; int tmp; int count = 0; int highPos = -1; int lowPos = -1; int flag = 1; printf(" Input : "); scanf("%d" , &num); int i = 0; /*******************核心代码*********************/ while(i != 32 ) { tmp = num&(1<<i); if(tmp) { highPos = i; count++; if(flag) { lowPos = i; flag = 0; } } i++; } /************************************************/ printf(" NUMBER: %d\n" , num); printf(" BITS: %d\n" , count); if(count >= 1) {//如果有1 printf("HIGHEST 1: %d\n" , highPos); printf(" LOWEST 1: %d\n" , lowPos); } else {//没有1 printf("HIGHEST 1: \n"); printf(" LOWEST 1: \n"); } return 0; }
2、编写程序把一个实型二进制数中 1 的个数,最高位 1 的位置 和 最低位 1 的位置 显示出来。
程序接受用户输入的一个整数(分别正数一个,负数一个)
输出该整数,以及其中1的个数,最高位1的位置,最低位1的位置。
用GCC编译程序运行,检查程序运行是否正确。
/*编写程序 把一个实型二进制数中1的个数,最高位1的位置和最低位1的位置显示出来。 程序接受用户输入的一个实型(分别正数一个,负数一个), 输出该实型, 以及其中1的个数, 最高位1的位置, 最低位1的位置。 root@kjf:/mnt/hgfs/workPlace/01_computer/20170914# ./a.out Input : 8.25 NUMBER: 0100 0001 0000 0100 0000 0000 0000 0000 BITS: 3 HIGHEST 1: 30 LOWEST 1: 18 */ #include <stdio.h> #define print_float(a) print_bitxx(a, 4) //访问对象地址,访问对象大小float为4字节 int count; int posHex; int highPos; int lowPos; int highFlag; int lowFlag; //判断小端模式 int is_little_endian() { short int x = 0x0001; return ((char*)&x)[0]; } //访问对象地址,访问对象大小float为4字节。。。打印存储的二进制数 void print_bitxx(const void *a, int bytes) { int bit; const unsigned char *pos = (const unsigned char *)a; int i, j; int max_i; max_i = bytes - 1; if(is_little_endian()) {//此程序只适用小端模式,因为是根据指针访问存储数据 for(i=max_i; i>=0; i--) { for(j=7; j>=0; j--) { bit= ((pos[i] & (1 << j)) ? 1 : 0); printf("%d", bit); /************************************/ if(bit == 1) {//如果是1 if(highFlag == 0) { highFlag = 1; highPos = posHex; } lowPos = posHex; count++; } posHex--; /************************************/ if (j == 4 || j == 0) printf(" "); } printf(" "); } } printf("\n"); } int main(int argc , char *argv[]) { float num = 0; /*************参数初始化************/ count = 0; posHex = 31; highPos = -1; lowPos = -1; highFlag = 0; lowFlag = 0; /***********************************/ printf(" Input : "); scanf("%f" , &num); /***********************************/ printf(" NUMBER: "); print_float(&num); printf(" BITS: %d\n" , count); if(count >= 1) {//如果有1 printf("HIGHEST 1: %d\n" , highPos); printf(" LOWEST 1: %d\n" , lowPos); } else {//没有1 printf("HIGHEST 1: \n"); printf(" LOWEST 1: \n"); } return 0; }