如何正确使用float和double?

1、典型问题

问题一:条件判断超预期

1System.out.println(1f == 0.9999999f) // false 2System.out.println(1f == 0.99999999f) // true

问题二:数据转换超预期

1float f = 1.1f; 2double d = (double)f; 3System.out.println(f); // 1.1 4System.out.println(d); // 1.100000023841858

问题三:基本运算超预期

1System.out.println( 0.2 + 0.7 ); // 0.8999999999999999

问题四:数据自增超预期

1float f1 = 8455263f; // 7位数 2for (int i = 0; i < 10; i++) { 3 System.out.println(f1); 4 f1++; 5} 6// 打印:8455263.0 7// 打印:8455264.0 8// 打印:8455265.0 9// 打印:8455266.0 10// 打印:8455267.0 11// 打印:8455268.0 12// 打印:8455269.0 13// 打印:8455270.0 14// 打印:8455271.0 15// 打印:8455272.0 16 17float f2 = 84552631f; // 8位数 18for (int i = 0; i < 10; i++) { 19 System.out.println(f2); 20 f2++; 21} 22// 打印:8.4552632E7 23// 打印:8.4552632E7 24// 打印:8.4552632E7 25// 打印:8.4552632E7 26// 打印:8.4552632E7 27// 打印:8.4552632E7 28// 打印:8.4552632E7 29// 打印:8.4552632E7 30// 打印:8.4552632E7 31// 打印:8.4552632E7

2、浮点数的精度问题

浮点数在计算机中的存储方式遵循IEEE 754 浮点数计数标准,可以用科学计数法表示为: 1654516997147 对于float和double两种浮点数在内存中的存储结构如下图所示: image image 1、符号部分(S)

  • 0-正
  • 1-负

2、阶码部分(E)(指数部分)

  • 对于float型浮点数,指数部分8位,考虑可正可负,因此可以表示的指数范围为-127 ~ 128
  • 对于double型浮点数,指数部分11位,考虑可正可负,因此可以表示的指数范围为-1023 ~ 1024

3、尾数部分(M) 浮点数的精度是由尾数的位数来决定的:

  • 对于float型浮点数,尾数部分23位,换算成十进制就是 2^23=8388608,所以十进制精度只有6 ~ 7位;
  • 对于double型浮点数,尾数部分52位,换算成十进制就是 2^52 = 4503599627370496,所以十进制精度只有15 ~ 16位

所以,上述0.99999999f超出float型浮点数据的精度范围。

3、如何解决精度问题

  • 用字符串或者数组解决多位数问题
  • Java的大数类:BigDecimal、BigInteger
1BigDecimal num3 = new BigDecimal( Double.toString( 1.0f ) ); 2BigDecimal num4 = new BigDecimal( Double.toString( 0.99999999f ) ); 3System.out.println( num3 == num4 ); // 打印 false 4 5BigDecimal num1 = new BigDecimal( Double.toString( 0.2 ) ); 6BigDecimal num2 = new BigDecimal( Double.toString( 0.7 ) ); 7 8// 加 9System.out.println( num1.add( num2 ) ); // 打印:0.9 10 11// 减 12System.out.println( num2.subtract( num1 ) ); // 打印:0.5 13 14// 乘 15System.out.println( num1.multiply( num2 ) ); // 打印:0.14 16 17// 除 18System.out.println( num2.divide( num1 ) ); // 打印:3.5

局限性:大数类的运算效率肯定是不如原生类型效率高,代价还是比较昂贵的,是否选用需要根据实际场景来评估。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前