为什么float浮点类型数比int,long表示的范围要大?

您所在的位置:网站首页 种与类哪个范围大 为什么float浮点类型数比int,long表示的范围要大?

为什么float浮点类型数比int,long表示的范围要大?

2024-07-16 23:32| 来源: 网络整理| 查看: 265

转自:https://blog.csdn.net/sky1988818/article/details/86539119

背景:float 底层用4个字节32位来表示,为什么范围比int,long还要大?

       整数在计算机底层采用补码的形式表示,除去首位的符号位,剩余的位数即表示数值的范围,也就是位数越多,范围越大,那么对于单精度浮点数float,和双精度浮点数double,它们底层的数据结构是什么,它们的范围又是如何计算的,它们的精度范围又是多少那,接下来将从6方面进行阐述。

1.IEEE754浮点数标准  

  IEEE754标准包含一组实数的二进制表示法。它有三部分组成:符号位, 指数位, 尾数位

  用float来举例,三种精度的浮点数各个部分位数如下:

   

  第一部分用来存储符号位(sign),用来区分正负数,0正1负。

  第二部分用来存储指数(exponent),指数也有正负之分,指数位确定大小范围。

  第三部分用来存储小数(fraction),小数位决定了计算精度,因为小数位能表示的数越大,精度越大,数值越准确。

  备注:浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”

2 第二部分(指数位确定范围)

       需要注意的是指数可能是负数,也有可能是正数,即指数是有符号整数,而有符号整数的计算是比无符号整数麻烦的。所以为了减少不必要的麻烦,在实际存储指数的时候,需要把指数转换成无符号整数。

  那么怎么转换呢?注意到float的指数部分是8位,则指数的取值范围是 -126到+127,为了消除负数带来的实际计算上的影响(比如比较大小,加减法等),可以在实际存储的时候,给指数做一个简单的映射,加上一个偏移量,比如float的指数偏移量为127,对应的double类型,存储的时候指数偏移量是1023,这样就不会有负数出现了。

3 第三部分(小数位确定精度)

     float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。  float:2^23 = 8388608,一共七位,由于最左为1的一位省略了,这意味着最多能表示8位数,但绝对能保证的为7位,也即float的精度为7~8位有效数字(算上整数的一位),不算整数位的话能只有7位,所以能准确表示的10进制也就6位。  double:2^52 = 4503599627370496,一共16位,同理,double的精度为16~17位,能准确表示的10进制也就15位。

4 注意点

  程序中应尽量避免浮点数的比较,例如System.out.println(2.00-1.10==0.90),永远返回false.  float、double类型的运算往往都不准确。

5 正确的方式

     利用整数来表示小数int或者long,例如1.01元,则可以以分为单位来表示。  利用BigDecimal进行浮点型运算,但是注意一定要使用String类型的构造方法,如果使用浮点型构造方法也不能得到准确的结果。

6 福利彩蛋(浮点数保留2位的几种方法) 1 double dd = (double) (Math.round(1/(float)num*100)/100.0); //先乘以100后除以100,对浮点数做进位处理。 2 DecimalFormat df=new DecimalFormat("###.00") 3 String ss = String.format("%1.2f", 1.1256); 4 NumberFormat ddf1=NumberFormat.getNumberInstance() ; ddf1.setMaximumFractionDigits(2); 5 BigDecimal b = new BigDecimal(T); T = b.setScale(2,BigDecimal.ROUND_HALF_UP).floatValue(); 7 个人补充说明(非转载部分)

  float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。

     如果使用sprintf_s将数字以十进制格式化到字符串中,float类型数据需要至少定义成长度为42的字节数组,其中以-3.40E+38为极限长度,字符串格式形于“-0.0000.....34”,如char floatBuffer[43]。double类型数据需要至少定义成长度314的字节数组,如char doubleBuffer[314];

  这一条是我在测试PLC数据读取碰到的问题,即使用sprintf_s将float格式化成字符串输出,在模拟环境中能正常运行,但是接入PLC系统后总是报Buffer Is Too Small,这是典型的字符串长度超出缓冲区问题,分析log我发现定义的Buffer长度为32个字节,但是格式化float成字符串的长度是52,问题显而易见。部分log如下:

1 2020-04-10 18:37:12.836 [I] MachineNo = [0] 2 2020-04-10 18:37:12.838 [I] ACT_CHARGE_ID = [] 3 2020-04-10 18:37:12.841 [I] MachineStatus = [2] 4 2020-04-10 18:37:12.843 [I] ACT_PROCESS = [-28671] 5 2020-04-10 18:37:12.846 [I] ACT_CRU_ID = [] 6 2020-04-10 18:37:12.848 [I] ACT_INGOT_ID = [] 7 2020-04-10 18:37:12.851 [I] ACT_RCP_NAME = [] 8 2020-04-10 18:37:12.853 [I] Header = [0] 9 2020-04-10 18:37:12.856 [I] Timestamp = [] 10 2020-04-10 18:37:12.858 [I] User_Name = [] 11 2020-04-10 18:37:12.860 [I] ACT_XT_SPD = [0.000000] 12 2020-04-10 18:37:12.863 [I] ACT_XT_ROT = [0.000000] 13 2020-04-10 18:37:12.866 [I] ACT_XT_POS = [7046656236157048700000.000000] 14 2020-04-10 18:37:12.870 [I] ACT_CR_SPD = [0.000000] 15 2020-04-10 18:37:12.873 [I] ACT_PRS_CLF = [2245535288003289000000000000000000000.000000] 16 2020-04-10 18:37:12.878 [I] ACT_CR_ROT = [0.000000] 17 2020-04-10 18:37:12.885 [I] ACT_CR_POS = [4242751136953196900000.000000] 18 2020-04-10 18:37:12.889 [I] ACT_TOT_XT_LGH = [0.000000] 19 2020-04-10 18:37:12.893 [I] ACT_HTR_1_PWR = [0.000000] 20 2020-04-10 18:37:12.897 [I] ACT_HTR_1_TMP = [0.000000] 21 2020-04-10 18:37:12.900 [I] ACT_HTR_2_PWR = [0.000000] 22 2020-04-10 18:37:12.904 [I] ACT_MAG_1_CUR = [0.000000] 23 2020-04-10 18:37:12.907 [I] ACT_MAG_2_CUR = [0.000000] 24 2020-04-10 18:37:12.910 [I] ACT_GAS_1_FLW = [0.000000] 25 2020-04-10 18:37:12.913 [I] ACT_GAS_2_FLW = [0.000000] 26 2020-04-10 18:37:12.916 [I] ACT_PRS_CGT = [-0.000000] 27 2020-04-10 18:37:12.919 [I] FAULT[2] = [409] 28 2020-04-10 18:37:12.922 [I] ACT_XT_DIA = [0.000000] 29 2020-04-10 18:37:12.925 [I] ACT_XT_LEN_MM = [0.000000] 30 2020-04-10 18:37:12.929 [I] CRU_QRZ_TRANS_RAD = [0.000000] 31 2020-04-10 18:37:12.932 [I] CHARGE_WGT = [0.000000] 32 2020-04-10 18:37:12.935 [I] FAULT[1] = [410] 33 2020-04-10 18:37:12.937 [I] CRU_QRZ_WALL_THICKN = [0.000000] 34 2020-04-10 18:37:12.941 [I] FAULT[3] = [397] 35 2020-04-10 18:37:12.944 [I] CRU_QRZ_BOT_THICKN = [0.000000] 36 2020-04-10 18:37:12.947 [I] CRU_GRAPH_BOT_RAD = [-0.000000] 37 2020-04-10 18:37:12.951 [I] CRU_GRAPH_INNER_DIA = [36749372959343247000.000000] 38 2020-04-10 18:37:12.955 [I] FAULT0 = [0] 39 2020-04-10 18:37:12.958 [I] FAULT[4] = [398] 40 2020-04-10 18:37:12.961 [I] FAULT[5] = [405] 41 2020-04-10 18:37:12.963 [I] FAULT[6] = [404] 42 2020-04-10 18:37:12.966 [I] FAULT[7] = [401] 43 2020-04-10 18:37:12.968 [I] FAULT[8] = [400] 44 2020-04-10 18:37:12.971 [I] FAULT[9] = [416] 45 2020-04-10 18:37:12.973 [I] FAULT[10] = [135]


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3