无论在什么业务中,钱?是非常重要的东西,对账的时候一定要对的上,不能这边少一分钱那边多一分钱。对于数值的计算,尤其是小数,floatedouble都是禁止使用的。

阿里强制要求存放小数时使用 decimal,禁止使用 float 和 double。

说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

处理方式可以为:mysql 可以用 decimal ,如果你是用 java, 在商业计算中我们要用 java.math.BigDecimal,注意:如果需要精确计算,非要用String来构造BigDecimal不可!

那么到底是什么情况?为什么我们的账户一会少一分一会多一分(往往是少一分),如何解决呢?

一个例子说明

废话不多说,当我们拿着一块钱去买了一根9毛的棒冰会发生啥?本来只剩1毛钱就不多了,老板还扣我0.000....0002分?上图:

问题原因

无论是我们本文提到的double,还是float,都是浮点数。

在计算机科学中,浮点(英语:floating point,缩写为FP)是一种对于实数的近似值数值表现法,由一个有效数字(即尾数)加上幂数来表示,通常是乘以某个基数的整数次指数得到。以这种表示法表示的数值,称为浮点数(floating-point number)。

划重点,⭐⭐⭐其实我觉得很好理解,我们之前说过,计算机计算加减乘除啊,都是用的加法器,实质都是二进制的加法处理。那么这里就有一个二进制表示的问题。试想,4,2,8之流都是2的幂次方,可以完美用二进制表示,计算当然不会出现问题。对于0,1,3,5之类也都可以用二进制来表示出来,所以,整数肯定是没问题的。

但是对于小数呢?1(2的0次方)、0.5(2的-1次方)、0.25(2的-2次方)、0.75(2的-1次方+2的-2次方),那都是可以转换成二进制的小数:

但是如十进制的0.1,就无法用二进制准确的表示出来(你用2的次方来凑凑?)。因此只能使用近似值的方式表达。如果我们尝试着把10进制的0.1转化成二进制,会怎么转呢?

在十进制中,0.1如何计算出来的呢?

0.1 = 1 ÷ 10

那么二进制中也是同理:

1 ÷ 1010

我们回到小学的课堂,来列竖式吧:

       0.000110011...      ------------------1010 ) 1 00001010       ------11001010          ----100001010            -----11001010              ----10

很显然,除不尽,除出了一个无限循环小数:二进制的 0.0001100110011...

有的同学表示怀疑?这结果正确?

我写在这里当然正确啦,前面标注了是二进制,小数点后面一位就是-1次方依次计算,我们的0.1是不是介于(2的-3次方)和(2的-4次方)之间,那么显然是从小数点第四个开始有1。

好了,那么,如何在计算机中表示这个无限不循环的小数呢?只能考虑按照不同的精度保留不同的位数。

我们知道float是单精度的(JAVA中是32位),double是双精度的(JAVA中是64位)。不同的精度,其实就是保留的有效数字位数不同,保留的位数越多,精度越高。

所以,浮点数在Java中是无法精确表示的,因为大部分浮点数转换成二进制是一个无限不循环的小数,只能通过保留精度的方式进行近似表示。

问题的解决

String 构造方法是完全可预知的:写入 newBigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。

使用BigDecimal(String val)

//加法public static BigDecimal add(double v1, double v2){    BigDecimal b1 = new BigDecimal(Double.toString(v1));    BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.add(b2);}

//减法public static BigDecimal sub(double v1,double v2){    BigDecimal b1 = new BigDecimal(Double.toString(v1));    BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.subtract(b2);}

//乘法public static BigDecimal mul(double v1,double v2){    BigDecimal b1 = new BigDecimal(Double.toString(v1));    BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.multiply(b2);}

//除法public static BigDecimal div(double v1,double v2){    BigDecimal b1 = new BigDecimal(Double.toString(v1));    BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.divide(b2,2,BigDecimal.ROUND_HALF_UP);//四舍五入,保留2位小数,应对除不尽的情况}

那么,上面的精度丢失问题就迎刃而解了。但是除不尽怎么办?比如10.0除以这里的3.0,保留小数点后三位有效数字:

那么,每个用户得到的都是3.333元,三个用户加起来是得不到10块钱的。

对于除法,始终会产生除不尽的情况怎么办?有个词叫轧差

什么意思呢?举个简单例子。假如现在需要把10元分成3分,如果是10除以3这么除,会发现为3.33333无穷尽的3。这些数字完全无法在程序或数据库中进行精确的存储。

简单理解就是,当除不尽或需去除小数点的时候,前面的n-1笔(这里n=3)做四舍五入。最后一笔做兜底(总金额减去前面n-1笔之和)。这样保证总金额的不会丢失。

比如10块钱,三个用户分,前面两个用户只能各分到3.333块钱,最后一个用户分到3.334块钱。保证总额不变。是不是感觉很机智

好了,我们可以准确地管理我们的钱了。不过针对这个钱的问题,更机智的我选择保存钱的时候用分为单位来操作和保存,能少一事就少一事吧。当然了,有的时候必须用到小数的时候,请记住我们该如何使用哦~

bigdecimal取小数部分_小数精度丢失问题分析和解决相关推荐

  1. JavaScript 进制之间的转换、大数或小数精度丢失、js不同进制的表示(分享)

    文章目录 1. toString(radix) 2. parseInt(string, radix) 3. 0.1 + 0.2 !=== 0.3 4. BigInt() 5. js不同进制的表示 1. ...

  2. js浮点数精度丢失问题及如何解决js中浮点数计算不精准

    js浮点数精度丢失问题及如何解决js中浮点数计算不精准 参考文章: (1)js浮点数精度丢失问题及如何解决js中浮点数计算不精准 (2)https://www.cnblogs.com/ranyonsu ...

  3. BigDecimal操作double、float精度丢失问题

    一.问题 最近使用BigDecimal进行数值加减运算的时候踩了一个小坑:BigDecimal操作double.float数值时精度丢失. 举个例子: public static void main( ...

  4. bigdecimal取小数部分_Java中BigDecimal保留两位小数点有哪些方法

    Java中BigDecimal保留两位小数点有哪些方法?今天就跟长沙尚学堂小编一起来好好的了解下,到底有哪些方法,希望你至少能够掌握好一种. 保留两位小数{ 方法一:{ double c=3.1542 ...

  5. PHP怎样防止小数点精度不丢失,javascript小数精度丢失的完美解决方法

    @H_3010@ 原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. @H301_0@javascript(js)的小数点加减乘除 ...

  6. php json_encode小数精度丢失的问题

    <?php$arr = ['a'=>2.4,'b'=>3 ];print_r($arr);/*** ([a] => 2.4[b] => 3)*/var_dump(json ...

  7. 企业网站百度排名突然丢失原因分析及解决方法-www.bjrp.com

    一.搜索引擎算法更新 今年随着360搜索引擎市场不断的上升,搜狗和搜搜的合并,百度搜索引擎市场面临巨大的竞争和压力,不得不推陈出新,更新算法,满足用户的需求,提升搜索引擎的用户体验,(瑞普网络-北京网 ...

  8. c 中连接mysql登录不成功_数据库连接失败的原因分析及解决办法 | 学步园

    如何来解决三个最常见的连接错误. 第一个错误"SQL Server 不存在或访问被拒绝"通常是最复杂的,错误发生的原因比较多,需要检查的方面也比较多.一般说来,有以下几种可能性: ...

  9. 连接mysql服务验证失败_数据库连接失败的原因分析及解决办法

    如何来解决三个最常见的连接错误. 第一个错误"SQL Server 不存在或访问被拒绝"通常是最复杂的,错误发生的原因比较多,需要检查的方面也比较多.一般说来,有以下几种可能性: ...

最新文章

  1. 用Python来分析5天破10亿的哪吒,为啥这么火?
  2. 开发笔记7 | 部署 Go 应用程序到阿里云 ECS
  3. Python 基础篇-简单的异常捕获
  4. pythondistinct教程_mongodb如何执行distinct
  5. 知其然不知其所以然的悲惨后果【EF CodeFirst 实体关系两日游】
  6. 【webservice】spring整合webservice RS风格
  7. 如何在国内下载Eclipse及其插件
  8. redis源码剖析(五)—— 字符串,列表,哈希,集合,有序集合
  9. Linux之V4L2基础编程
  10. OpenCV中直方图均衡化
  11. 前端笔记-freemarker模板获取后端数据及提交数据
  12. 内部类及内部类什么时候使用
  13. SpringCloud大致架构
  14. WebBrowser keystroke
  15. ERP项目实施记录05
  16. MyBatis 动态 SQL(认真看看, 以后写 SQL 就爽多了)
  17. 路由模块router实现step1
  18. 计算机控制技术课后题答案,计算机控制技术课后习题答案
  19. 代码雨【code rain】 cmd 命令快速实现 + java 实现
  20. 内涵图:从明天起,做一个有内涵的人

热门文章

  1. 【渝粤教育】 国家开放大学2020年春季 2246社会工作概论 参考试题
  2. 【渝粤教育】 国家开放大学2020年春季 2772家畜环境卫生与设施 参考试题
  3. 【渝粤题库】国家开放大学2021春2175市场营销学题目
  4. 【渝粤题库】国家开放大学2021春2528监督学题目
  5. android 打印kernel log,android8.0 kernel4.9.44 各层log打开
  6. linux服务器防端口扫描,linux下防止syn***,端口扫描和死亡之ping
  7. oracle多条sql语句常量,如何在Oracle中一次执行多条sql语句
  8. 信息技术与计算机文化的问题,信息技术与计算机文化
  9. php按钮css样式,CSS 按钮
  10. OpenMP之双重for循环并行计算改进