Java基础---为什么不能用浮点数表示金额

目录

缘由

十进制转二进制

不是所有数都能用二进制表示

IEEE 754

避免精度丢失


  • 缘由

  • 因为不是所有的小数都能用二进制表示,所以,为了解决这个问题,IEEE提出了一种使用近似值表示小数的方式,并且引入了精度的概念
  • 这就是我们所熟知的浮点数
  • 所以,浮点数只是近似值,并不是精确值,所以不能用来表示金额
  • 否则会有精度丢失
  • 十进制转二进制

  • 首先看一下,如何把十进制整数转换成二进制整数?
  • 十进制整数转换为二进制整数采用"除2取余,逆序排列"法
  • 具体做法是:
    • 用2整除十进制整数,可以得到一个商和余数
    • 再用2去除商,又会得到一个商和余数,如此进行,直到商为小于1时为止
    • 然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来
  • 如想要把127转换成二进制,做法如下:

  • 那么,十进制小数转换成二进制小数,又该如何计算呢?
  • 十进制小数转换成二进制小数采用"乘2取整,顺序排列"法
  • 具体做法是:
    • 用2乘十进制小数,可以得到积
    • 将积的整数部分取出,再用2乘余下的小数部分,又得到一个积
    • 再将积的整数部分取出,如此进行,直到积中的小数部分为零,此时0或1为二进制的最后一位
    • 或者达到所要求的精度为止
  • 所以,十进制的0.625对应的二进制就是0.101

  • 不是所有数都能用二进制表示

  • 知道了如何将一个十进制小数转换成二进制,那么是不是计算就可以直接用二进制表示小数了呢?
  • 前面的例子中0.625是一个特列,那么还是用同样的算法,请计算下0.1对应的二进制是多少?

  • 可以发现,0.1的二进制表示中出现了无限循环的情况,也就是(0.1)10 = (0.000110011001100…)2
  • 这种情况,计算机就没办法用二进制精确的表示0.1了
  • 也就是说,对于像0.1这种数字,是没办法将他转换成一个确定的二进制数的
  • IEEE 754

  • 为了解决部分小数无法使用二进制精确表示的问题,于是就有了IEEE 754规范
  • IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用
  • 小提示:
  • 浮点数和小数并不是完全一样的,计算机中小数的表示法,其实有定点和浮点两种
  • 因为在位数相同的情况下,定点数的表示范围要比浮点数小
  • 所以在计算机科学中,使用浮点数来表示实数的近似值
  • IEEE 754规定了四种表示浮点数值的方式:
    • 单精确度(32位)
    • 双精确度(64位)
    • 延伸单精确度(43比特以上,很少使用)
    • 与延伸双精确度(79比特以上,通常以80位实现)
  • 其中最常用的就是32位单精度浮点数和64位双精度浮点数
  • IEEE并没有解决小数无法精确表示的问题,只是提出了一种使用近似值表示小数的方式,并且引入了精度的概念
  • 浮点数是一串0和1构成的位序列(bit sequence),从逻辑上用三元组{S,E,M}表示一个数N,如下图所示:

  • S(sign)表示N的符号位
  • 对应值s满足:
    • n>0时,s=0
    • n≤0时,s=1
  • E(exponent)表示N的指数位,位于S和M之间的若干位
  • 对应值e值也可正可负
  • M(mantissa)表示N的尾数位,恰好,它位于N末尾
  • M也叫有效数字位(significand)、系数位(coefficient),甚至被称作"小数"
  • 则浮点数N的实际值n由下方的式子表示:

  • 上面这个公式看起来很复杂,其中符号位和尾数位还比较容易理解,但是这个指数位就不是那么容易理解了
  • 其实也不用太过于纠结这个公式,只需要知道对于单精度浮点数,最多只能用32位字符表示一个数字,双精度浮点数最多只能用64位来表示一个数字
  • 而对于那些无限循环的二进制数来说,计算机采用浮点数的方式保留了一定的有效数字,那么这个值只能是近似值,不可能是真实值
  • 至于一个数对应的IEEE 754浮点数应该如何计算,不是本文的重点,这里就不再赘述了,过程还是比较复杂的,需要进行对阶、尾数求和、规格化、舍入以及溢出判断等
  • 但是这些其实不需要了解的太详细,只需要知道,小数在计算机中的表示是近似数,并不是真实值
  • 根据精度不同,近似程度也有所不同
  • 如0.1这个小数,他对应的在双精度浮点数的二进制为:0.00011001100110011001100110011001100110011001100110011001
  • 0.2这个小数0.00110011001100110011001100110011001100110011001100110011
  • 所以两者相加:

  • 转换成10进制之后得到:0.30000000000000004!
  • 避免精度丢失

  • 在Java中,使用float表示单精度浮点数,double表示双精度浮点数,表示的都是近似值
  • 所以,在Java代码中,千万不要使用float或者double来进行高精度运算,尤其是金额运算,否则就很容易产生资损问题
  • 为了解决这样的精度问题,Java中提供了BigDecimal来进行精确运算

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/4611.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day6——Web安全基础

网络安全学习笔记Day6 Web安全基础 一.Web简介什么是Web?什么是因特网?互联网,因特网,万维网的关系万维网构想的诞生http协议URL 二.Web发展史Web1.0Web2.01.0与2.0的区别Web1.0的安全漏洞Web2.0的安全漏洞 三.杂项门户网站静态页…

tomcat接入skywalking

tomcat接入skywalking 一、说明二、步骤2.1 准备java-agent包2.2 tomcat部署2.2.1 下载2.2.2 tomcat修改catalina.sh文件2.2.3 tomcat修改启动端口2.2.4 启动tomcat 三、验证四、问题排查4.1 tomcat的启动日志 一、说明 服务器中已经运行着skywalking,准备在同一台…

Spring Boot实战:拦截器和监听器的应用指南

当使用Spring Boot时,我们可以通过拦截器(Interceptor)和监听器(Listener)来实现对请求和响应的处理。拦截器和监听器提供了一种可插拔的机制,用于在请求处理过程中进行自定义操作,例如记录日志…

智慧文旅VR全景展示,深度VR沉浸式体验

导语: 智慧文旅VR全景展示为我们带来了一种独特的旅行体验,让我们可以穿越时空、身临其境地感受历史、艺术和自然的魅力。 在这个数字化时代,智慧文旅VR全景展示成为了旅游界的新宠,它让我们能够以一种前所未有的方式探索世界&am…

Django之ORM

一、Django模型层之ORM介绍 使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(增、删、改、查),而一旦谈到数据的管理操作,就需要用到数据库管理软件,例如mysql、oracle、Microsoft S…

梁宁:VisionPro、GPT、Web3三件套齐备,元宇宙开启

本文内容整理自图灵社区对谈栏目直播,主题为 ChatGPT 真需求,从产品的第一性原理解析。 上篇内容回顾:梁宁:为什么中国没有像 ChatGPT 和 Vision Pro 这样的创新产品? 梁宁,产品战略专家,曾任湖…

【Linux】MySQL 主从复制与读写分离

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 MySQL 主从复制与读写分离 MySQL 主从复制与读写分离1、什么是读写分离2、为什么要读写分离3、什么时候要读写分离4、主从复制与读写分离5、mysql支持的复制类型6、主从复制的…

windows -- dos命令

文章目录 内部命令变量常用命令特殊命令符综合案例 外部命令 内部命令 操作系统的内部命令。 win r, 输入cmd 打开命令窗口; 如: dir,查看当前目录下的内容cd,切换目录copy, 拷贝echo,打印 变量 windo…

Flink中时间和窗口

文章目录 一、时间定义二、水位线(Watermark)1、概念2、水位线特征3、生成水位线3.1 水位线生成策略(Watermark Strategies)3.2 Flink 内置水位线生成器3.3 自定义水位线策略 4、水位线的传递 三、窗口(Window)1、概念2、窗口分类2.1 驱动类型分类2.2 窗…

高级SQL语句

目录 MySQL 高级(进阶) SQL 语句函数数学函数:聚合函数字符串函数: 连接查询inner join(内连接):left join(左连接):right join(右连接): CREATE VIEW(视图)UNION(联集)C…

字符串转字典类型时出现的NameError: name ‘false‘ is not defined

报错的原因 eval()函数不能够处理flase,null,true这个几个值 解决方法: 我的理解就是给false, null, true 赋一个eval可以处理的值然后在使用eval函数进行处理 global false, null, true false null true 完美解…

Kafka可视化平台EFAK搭建及使用

文章目录 1.EFAK可视化平台介绍2.搭建EFAK可视化平台2.1.安装JDK环境2.2.安装MySQL数据库2.3.下载EAK二进制安装包并部署2.4.配置EFAK连接Zookeeper集群2.5.调整Eagle启动文件中的变量信息2.6.启动EFAK可视化平台 3.使用EFAK可视化平台3.1.登陆EFAK可视化平台3.2.EFAK仪表盘展示…