当前位置: 首页 > news >正文

【你真的了解double和float吗】

在这里插入图片描述

🌈个人主页:努力学编程’
个人推荐:基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解
学好数据结构,刷题刻不容缓:点击一起刷题
🌙心灵鸡汤总有人要赢,为什么不能是我呢
!=外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

🌈🌈🌈一些有关float和double的奇怪现象

  • 现象一:条件判断超出预期
System.out.println(1f==0.9999999f);//输出结果  falseSystem.out.println(1f==0.99999999f); //输出结果  true
  • 现象二:数据转换超出预期
float f =1.1f;
double d=(double)f;
System.out.println(f);// 输出1.1
Sysout.out.println(d);// 输出1.100000023841858
  • 现象三: 基本计算超出了预期
System.out.println(0.2+0.7);
//输出  0.8999999999999999
  • 典型现象四:数据自增超出预期
float f1=8455263f
for(int i=0;i<10;i++){Sysout.out.println(f1);f1++;
} //此处正常打印f1相加后的值float f2=84552631f;
for(int i=0;i<10;i++){Sysout.put.println(f2);f2++;
}//输出的结果  8.4552632E7 //后面的每次运算之后结果仍为 8.4552632E7 

以上情况,我们会发现其实关于float和double很多基础的操作,都可能会出现问题,所以公司或者银行系统一般不会将商品金额,订单交易,货币计算使用float或者double,浮点数的风险很大!!!

🌈🌈🌈原因分析

为什么会出现这些的情况呢,其实这就和java中存储浮点数的方式有关了,由于存储方式的缺陷往往会把浮点数的数据丢失。

分析现象一:

Sysout.out.println(1f==0.99999999f);  //输出  true

为何判断 1 和 0.99999999 的大小输出true?

我们知道关于1和0.99999999我们通过肉眼直接可以判断两者之间的关系,这里我们都是默认的是十进制进行的大小比较,但是计算机的底层逻辑都是基于1010010101这样的二进制形式进行存储数据的。

所以我们可以试图将这两个数转化为二进制,然后再进行大小的比较:
在这里插入图片描述
这是一个进制转换的网站:进制转换网站

🌈🌈🌈浮点数精度的问题

学过 《计算机组成原理》 这门课的小伙伴应该都知道,浮点数在计算机中的存储方式遵循IEEE 754 浮点数计数标准,可以用科学计数法表示为:
在这里插入图片描述

只要给出:符号(S)、阶码部分(E)、尾数部分(M) 这三个维度的信息,一个浮点数的表示就完全确定下来了,所以float和double这两种浮点数在内存中的存储结构如下所示:
在这里插入图片描述

⚡⚡⚡符号部分(s):

由0和1构成,0代表该数为正,1代表该数为负。

⚡⚡⚡阶码部分(E):

  • 针对float这种浮点数,他的指数部分有8位,可表示正数,也可以表达负数,因此,可以表述的指数的范围是-127~128
  • 对于double类型的浮点数,指数部分的大小为11位,这里既可以是正数也可以是负数,所以这里可以表示的指数范围是-1023~1024

⚡⚡⚡尾数部分(M)

其实一个浮点数的精度就是由尾数的尾数决定的:

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

所以我们上面说的例子中的数值0.99999999f,很明显已经超过了float型浮点数数据的精度范围,所以出现问题也是可以理解的。

⚡⚡⚡如何解决精度的问题

如果我们在日常的开发过程中涉及到商品金额,交易值,货币计算等一些对精度要求较高的场景应该怎么办呢?

方法一:使用字符串或者数组解决多位数的问题

相信如果你大量刷过算法题的话,应该都知道使用字符串或者数组代表大数是一个典型的解题思路。

这时候我们我们可以用字符串或者数组来表示这种大数,然后按照四则运算的规则来手动模拟出具体计算过程,中间还需要考虑各种诸如:进位、借位、符号等等问题的处理,确实十分复杂,本文不做赘述。

方法二:使用java大数类
JDK早已为我们考虑到了浮点数的计算精度问题,因此提供了专用于高精度数值计算的大数类来方便我们使用。Java的大数类位于java.math包下:
在这里插入图片描述
可以看到,常用的BigInteger 和 BigDecimal就是处理高精度数值计算的一种很有效的方法。

BigDecimal num3 = new BigDecimal( Double.toString( 1.0f ) );
BigDecimal num4 = new BigDecimal( Double.toString( 0.99999999f ) );
System.out.println( num3 == num4 );  // 打印 falseBigDecimal num1 = new BigDecimal( Double.toString( 0.2 ) );
BigDecimal num2 = new BigDecimal( Double.toString( 0.7 ) );// 加
System.out.println( num1.add( num2 ) );  // 打印:0.9// 减
System.out.println( num2.subtract( num1 ) );  // 打印:0.5// 乘
System.out.println( num1.multiply( num2 ) );  // 打印:0.14// 除
System.out.println( num2.divide( num1 ) );  // 打印:3.5

但是,BigInteger 和 BigDecimal这种大数类的运算效率相对于原生类型效率高,代价还是比较高的,所以大家要理性使用~

相关文章:

  • 目标检测中损失函数的精妙作用:精确度与鲁棒性的双重保障
  • 九浅一深Jemalloc5.3.0 -- ⑨浅*gc
  • 如何在Laravel中实现数据验证:确保数据准确性的最佳实践
  • 【Vue报错】v-bind动态绑定src无效
  • NLP+LLM从入门到精通系列
  • 阿里Qwen2-72B大模型已是开源榜的王者,为什么还要推出其他参数模型,被其他模型打榜?
  • 【ssh】permission denied, please try again.
  • 【Go语言入门学习笔记】Part7.闭包和defer关键字
  • 从华为和特斯拉之争,看智能驾驶的未来
  • Java 线程池之 ScheduledThreadPool
  • 如何在Perl中进行条件判断:掌握Perl条件语句的艺术
  • 稳定性四—NE流程及分析方法
  • HandlerMethodArgumentResolver :深入spring mvc参数解析机制
  • JAVA:文件防重设计指南
  • 商用全面提速,5G新通话进入普及阶段!
  • 2017届校招提前批面试回顾
  • 2019年如何成为全栈工程师?
  • css布局,左右固定中间自适应实现
  • ES6 ...操作符
  • ES6之路之模块详解
  • JAVA SE 6 GC调优笔记
  • JS学习笔记——闭包
  • JS专题之继承
  • Material Design
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • 阿里云应用高可用服务公测发布
  • 测试如何在敏捷团队中工作?
  • 第2章 网络文档
  • 前端知识点整理(待续)
  • 系统认识JavaScript正则表达式
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 译有关态射的一切
  • 运行时添加log4j2的appender
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • ${ }的特别功能
  • (1)常见O(n^2)排序算法解析
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (实战篇)如何缓存数据
  • (学习日记)2024.01.09
  • (原创)可支持最大高度的NestedScrollView
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • .jks文件(JAVA KeyStore)
  • .net core 6 集成和使用 mongodb
  • .NET Core 中的路径问题
  • .NET命令行(CLI)常用命令
  • /bin/bash^M: bad interpreter: No such file ordirectory
  • ?php echo ?,?php echo Hello world!;?
  • @EnableConfigurationProperties注解使用
  • @Repository 注解
  • [].shift.call( arguments ) 和 [].slice.call( arguments )