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

下面这个代码,我很喜欢,其中有很多思想,对我来说很有用,膜拜下某大神

  1. #include <stdio.h>
  2.  
  3. #define print_float(a) print_bitxx(a, 4)
  4. #define print_int(a) print_bitxx(a, 4)
  5.  
  6. #define print_double(a) print_bitxx(a, 8)
  7.  
  8. int is_little_endian()
  9. {
  10. short int x = 0x0001;
  11. return ((char*)&x)[];
  12. }
  13.  
  14. void print_bitxx(const void *a, int bytes)
  15. {
  16. const unsigned char *pos = (const unsigned char *)a;
  17. int i, j;
  18. int max_i;
  19. max_i = bytes - ;
  20. if(is_little_endian())
  21. {
  22. for(i=max_i; i>=; i--)
  23. {
  24. for(j=; j>=; j--)
  25. {
  26. printf("%d", ((pos[i] & ( << j)) ? : ));
  27. if (j == || j == )
  28. printf(" ");
  29. }
  30. printf(" ");
  31. }
  32. }
  33. printf("\n");
  34. }
  35.  
  36. int main(int argc, char **argv)
  37. {
  38. int a = 8.25;
  39. float b = 8.25;
  40. double c = 8.25;
  41.  
  42. print_int(&a);
  43. print_float(&b);
  44. print_double(&c);
  45. printf("%d\n", b == (float) c);
  46. printf("%d\n", (double)b == (double) c);
  47. return ;
  48. }

然后就是我的学习时间了

1、编写程序把一个整型二进制数中 1 的个数,最高位1的位置和最低位1的位置显示出来。

程序接受用户输入的一个整数(分别正数一个,负数一个)

输出该整数,以及其中 1 的个数最高位 1 的位置最低位 1 的位置

用GCC编译程序运行,检查程序运行是否正确。

  1. /*编写程序
  2. 把一个整型二进制数中1的个数,最高位1的位置和最低位1的位置显示出来。
  3. 程序接受用户输入的一个整数(分别正数一个,负数一个),
  4. 输出该整数,
  5. 以及其中1的个数,
  6. 最高位1的位置,
  7. 最低位1的位置。
  8.  
  9. 一个示例的输出如下
  10. NUMBER: 2049
  11. BITS: 2
  12. HIGHEST 1: 11
  13. LOWEST 1: 0
  14. 据实验:输入的数字范围是(-2^31) 到 (2^31 - 1)
  15. -2147483648 到 2147483647
  16. 本代码移位运算测试,int 和unsigned int无区别
  17. */
  18. #include <stdio.h>
  19.  
  20. int main(int argc , char *argv[])
  21. {
  22. int num = ;
  23. int tmp;
  24.  
  25. int count = ;
  26. int highPos = -;
  27. int lowPos = -;
  28. int flag = ;
  29.  
  30. printf(" Input : ");
  31. scanf("%d" , &num);
  32.  
  33. int i = ;
  34. /*******************核心代码*********************/
  35. while(i != )
  36. {
  37. tmp = num&(<<i);
  38. if(tmp)
  39. {
  40. highPos = i;
  41. count++;
  42. if(flag)
  43. {
  44. lowPos = i;
  45. flag = ;
  46. }
  47. }
  48. i++;
  49. }
  50. /************************************************/
  51. printf(" NUMBER: %d\n" , num);
  52. printf(" BITS: %d\n" , count);
  53. if(count >= )
  54. {//如果有1
  55. printf("HIGHEST 1: %d\n" , highPos);
  56. printf(" LOWEST 1: %d\n" , lowPos);
  57. }
  58. else
  59. {//没有1
  60. printf("HIGHEST 1: \n");
  61. printf(" LOWEST 1: \n");
  62. }
  63.  
  64. return ;
  65. }

2、编写程序把一个实型二进制数中 1 的个数,最高位 1 的位置 和 最低位 1 的位置 显示出来。

程序接受用户输入的一个整数(分别正数一个,负数一个)

输出该整数,以及其中1的个数,最高位1的位置,最低位1的位置。

用GCC编译程序运行,检查程序运行是否正确。

  1. /*编写程序
  2. 把一个实型二进制数中1的个数,最高位1的位置和最低位1的位置显示出来。
  3. 程序接受用户输入的一个实型(分别正数一个,负数一个),
  4. 输出该实型,
  5. 以及其中1的个数,
  6. 最高位1的位置,
  7. 最低位1的位置。
  8.  
  9. root@kjf:/mnt/hgfs/workPlace/01_computer/20170914# ./a.out
  10. Input : 8.25
  11. NUMBER: 0100 0001 0000 0100 0000 0000 0000 0000
  12. BITS: 3
  13. HIGHEST 1: 30
  14. LOWEST 1: 18
  15. */
  16. #include <stdio.h>
  17.  
  18. #define print_float(a) print_bitxx(a, 4) //访问对象地址,访问对象大小float为4字节
  19.  
  20. int count;
  21. int posHex;
  22.  
  23. int highPos;
  24. int lowPos;
  25.  
  26. int highFlag;
  27. int lowFlag;
  28.  
  29. //判断小端模式
  30. int is_little_endian()
  31. {
  32. short int x = 0x0001;
  33. return ((char*)&x)[];
  34. }
  35.  
  36. //访问对象地址,访问对象大小float为4字节。。。打印存储的二进制数
  37. void print_bitxx(const void *a, int bytes)
  38. {
  39. int bit;
  40. const unsigned char *pos = (const unsigned char *)a;
  41. int i, j;
  42. int max_i;
  43. max_i = bytes - ;
  44. if(is_little_endian())
  45. {//此程序只适用小端模式,因为是根据指针访问存储数据
  46. for(i=max_i; i>=; i--)
  47. {
  48. for(j=; j>=; j--)
  49. {
  50. bit= ((pos[i] & ( << j)) ? : );
  51. printf("%d", bit);
  52. /************************************/
  53. if(bit == )
  54. {//如果是1
  55. if(highFlag == )
  56. {
  57. highFlag = ;
  58. highPos = posHex;
  59. }
  60. lowPos = posHex;
  61. count++;
  62. }
  63. posHex--;
  64. /************************************/
  65. if (j == || j == )
  66. printf(" ");
  67. }
  68. printf(" ");
  69. }
  70. }
  71. printf("\n");
  72. }
  73.  
  74. int main(int argc , char *argv[])
  75. {
  76. float num = ;
  77.  
  78. /*************参数初始化************/
  79. count = ;
  80. posHex = ;
  81.  
  82. highPos = -;
  83. lowPos = -;
  84.  
  85. highFlag = ;
  86. lowFlag = ;
  87.  
  88. /***********************************/
  89. printf(" Input : ");
  90. scanf("%f" , &num);
  91.  
  92. /***********************************/
  93. printf(" NUMBER: ");
  94. print_float(&num);
  95.  
  96. printf(" BITS: %d\n" , count);
  97. if(count >= )
  98. {//如果有1
  99. printf("HIGHEST 1: %d\n" , highPos);
  100. printf(" LOWEST 1: %d\n" , lowPos);
  101. }
  102. else
  103. {//没有1
  104. printf("HIGHEST 1: \n");
  105. printf(" LOWEST 1: \n");
  106. }
  107.  
  108. return ;
  109. }

http://canlynet.iteye.com/blog/1796889

__c语言__整型、实型的存储(十进制转二进制)的更多相关文章

  1. __c语言__结构体、共用体、枚举__笔记

    2017-09-16 21:14:09 结构体,共用体,枚举 1.结构体 把不同的类型整合成一个有机的整体,以便于引用,这个类型就叫做结构体 1)结构体变量的定义方式(3种)和引用成员变量: 定义一个 ...

  2. __c语言__测一段代码的运行时间

    2017-09-16 13:35:56 感觉很实用. /************************************** time ./a.out 命令所花费的real时间.user时间和 ...

  3. C语言的整型溢出问题

    整型溢出有点老生常谈了,bla, bla, bla… 但似乎没有引起多少人的重视.整型溢出会有可能导致缓冲区溢出,缓冲区溢出会导致各种黑客攻击,比如最近OpenSSL的heartbleed事件,就是一 ...

  4. c读入实型

    读入: 如果读入的数为整型,然后转为实型,则%lf 否则%f也可以 读出: %f,这样在codeblocks才能看到正确的结果

  5. Python基本数据类型之整型和布尔型

    整型和布尔型 获取对象的数据类型 1.type() 2.dir() 3.help() 4.在pycharm里面的操作 数字类型 int 创建: int() 接收数字字符串 .bit_lenght() ...

  6. SQLLite 可以通过SQL语言来访问的文件型SQL数据库

    Web Storage分为两类: - sessionStorage:数据保存在session 对象中(临时) - localStorage:数据保存在本地硬件设备中(永久) sessionStorag ...

  7. float:浮点型double:双精度实型decimal:数字型单精度浮点数(Single)双精度浮点数(double)

        单精度浮点数(Single) 双精度浮点数(double)       Decimal为SQL Server.MySql等数据库的一种数据类型,不属于浮点数类型,可以在定义时划定整数部分以及小 ...

  8. C++数据类型之实型(浮点型)&科学计数法

    实型(浮点型) **作用**:用于==表示小数== 浮点型变量分为两种: 1. 单精度float 2. 双精度double 两者的**区别**在于表示的有效数字范围不同. float类型数据,需在数据 ...

  9. 实型(浮点型):float、double

    实型(浮点型):float.double 实型变量也可以称为浮点型,浮点型变量是用来存储小数数值的.在C语言中,浮点型分为两种:单精度浮点型(float).双精度浮点型(double),但是doubl ...

随机推荐

  1. Lambda表达式树构建(上)

    概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可 ...

  2. HDU 5977 Garden of Eden (树形dp+快速沃尔什变换FWT)

    CGZ大佬提醒我,我要是再不更博客可就连一月一更的频率也没有了... emmm,正好做了一道有点意思的题,就拿出来充数吧=.= 题意 一棵树,有 $ n (n\leq50000) $ 个节点,每个点都 ...

  3. MediatR

    1.MediatR是什么? 微软官方eshopOnContainer开源项目中使用到了该工具, mediatR 是一种中介工具,解耦了消息处理器和消息之间耦合的类库,支持跨平台 .net Standa ...

  4. 【译】理解JavaScript中的柯里化

    译文开始 函数式编程是一种编程风格,这种编程风格就是试图将传递函数作为参数(即将作为回调函数)和返回一个函数,但没有函数副作用(函数副作用即会改变程序的状态). 有很多语言采用这种编程风格,其中包括J ...

  5. JMeter中BeanShell断言使用一

    Jmeter Ant Task如何让beanshell断言失败的详细信息展示在report里面 首先必须给beanshell断言添加FailureMessage if(${TotalClient_SS ...

  6. Openstack1 云计算与虚拟化概念

    一.云概念 二.虚拟化,云计算不等于虚拟化,但是云计算需要用到虚拟化的技术 1.服务器虚拟化 2.桌面虚拟化 3.应用虚拟化 三.区别 1.虚拟化是具体的技术. 2.云计算是交付使用的一种模式

  7. MySQL安装教程图解

    核心提示:下面的是MySQL安装的图解,用的可执行文件安装的,详细说明了一下! 下面的是MySQL安装的图解,用的可执行文件安装的,详细说明了一下! MySQL下载地址 打开下载的mysql安装文件m ...

  8. asp grid 增加和删除行数据

    <table border="0" cellpadding="0" cellspacing="0" style="width ...

  9. liunx命令简介

    图形界面和命令行要达到的目的是一样的,都是让用户控制计算机.然而,真正能够控制计算机硬件(CPU.内存.显示器等)的只有操作系统内核(Kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁 ...

  10. easyui+themeleaf 分页查询实现

    <!DOCTYPE html> <html xmlns:th="http://www.w3.org/1999/xhtml"> <head> &l ...