转载自: https://blog.csdn.net/JM_beizi/article/details/51775849?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

问题:为什么要用BigDecimal?

在java 中
1.11+0.9 = 1.2 ? NO result=1.2000000000000002
1.2/3=0.4? NO result=0.39999999999999997

这就是为什么要用BigDecimal的原因,对,因为直接用浮点数进行运算是不准确的,这和计算机对浮点数的存储有关系。

BigDecimal使用过程中的注意事项

这里主要是 BigDecimal 工具类的一个封装,对于其原理不做深究。使用中我觉得BigDecimal(double val) 是个需要注意的点。
其实java 的API 已经介绍的很详细了。首先看一下BigDecimal(double val)的API 介绍。

public BigDecimal(double val)

将 double 转换为 BigDecimal,后者是 double 的二进制浮点值准确的十进制表示形式。返回的 BigDecimal 的标度是使 (10scale × val) 为整数的最小值。

注:

  1. 此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

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

  3. 当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。

参数:
val - 要转换为 BigDecimal 的 double 值。
抛出:
NumberFormatException - 如果 val 为无穷大或 NaN。

我的理解:

  1. 通过官文的注释的第1,2点,我们应该能知道大概是什么情况。因为 new BigDecimal(double val)有不可预知性,所以直接用new BigDecimal(double val) 进行表示或者运算同样不能达到我们预期的结果。但是官方文档建议我们优先用可预知的new BigDecimal(String val)构造方法。

  2. 关于注释中的第三点。我觉得翻译的有偏差。我是这样理解的:当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换。BigDecimal (double val)不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为 String,而要获取这种分步骤转换的结果,建议使用 static valueOf(double) 方法。而这个方法是java api中提供的。

static valueOf(double) API介绍和源码

既然这里官方推荐使用 static valueOf(double) 方法,我们看下static valueOf(double)这个方法的api介绍和源码。

public static BigDecimal valueOf(double val)

使用 Double.toString(double) 方法提供的 double 规范的字符串表示形式将 double 转换为 BigDecimal。
注:这通常是将 double(或 float)转化为 BigDecimal 的首选方法,因为返回的值等于从构造 BigDecimal(使用 Double.toString(double) 得到的结果)得到的值。

参数:
val - 要转换为 BigDecimal 的 double。
返回:
其值等于或约等于 val 值的 BigDecimal。
抛出:
NumberFormatException - 如果 val 为无穷大或 NaN。

源码:

    /*** Returns a new {@code BigDecimal} instance whose value is equal to {@code* val}. The new decimal is constructed as if the {@code BigDecimal(String)}* constructor is called with an argument which is equal to {@code* Double.toString(val)}. For example, {@code valueOf("0.1")} is converted to* (unscaled=1, scale=1), although the double {@code 0.1} cannot be* represented exactly as a double value. In contrast to that, a new {@code* BigDecimal(0.1)} instance has the value {@code* 0.1000000000000000055511151231257827021181583404541015625} with an* unscaled value {@code 1000000000000000055511151231257827021181583404541015625}* and the scale {@code 55}.** @param val*            double value to be converted to a {@code BigDecimal}.* @return {@code BigDecimal} instance with the value {@code val}.* @throws NumberFormatException*             if {@code val} is infinite or {@code val} is not a number*/public static BigDecimal valueOf(double val) {if (Double.isInfinite(val) || Double.isNaN(val)) {throw new NumberFormatException("Infinity or NaN: " + val);}return new BigDecimal(Double.toString(val));}

这样就很清楚了。 因此看到网上有 new BigDecimal(Double.toString(double val)) 这种写法的 何不直接替换成 valueOf(double val)呢?

BigDecimal工具类

目前有的功能包括,“字符串转double类型”,“double四舍五入”,“BigDecimal四舍五入”,“double保留两位小数”,“BigDecimal保留两位小数”,“double的加、减、乘、除运算”,“BigDecimal 的加、减、乘、除运算”。

以后遇到需要的功能还会慢慢添加

    /*** Created by skx* <p/>* Double 数据类型处理工具类。目前基本包括“字符串转double 类型”,“四舍五入”,“保留两位小数”,“double类型的加、减、乘、除运算”*/public class DoubleFormatTool {/*** 字符串转Double** @param doubleString double类型的字符串* @return*/public static double strToDouble(String doubleString) {try {return Double.parseDouble(doubleString);} catch (Exception e) {return 0.0;}}/*** 得到一个Double 类型的数 四舍五入后保留小数点后两位.* <p/>* 这里调用的是  getRoundHalfUpDouble(String doubleString) 方法,* 而不是用  BigDecimal b = new BigDecimal(d);return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); 这样的方式来。* 主要原因是 BigDecimal(double) 的构造参数在使用的时候会存在精度不准确的情况,而在java中浮点运算本身就是不精确的,是用IEEE标准来表示的,当然这并不是所有的浮点数都不正确,而是有一部分不准确。* <p/>* API 中是这样解释的。public BigDecimal(double val)* 将 double 转换为 BigDecimal,后者是 double 的二进制浮点值准确的十进制表示形式。返回的 BigDecimal 的标度是使 (10scale × val) 为整数的最小值。* <p/>* 注:* 1.此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。* 2.另一方面,String 构造方法是完全可预知的:写入 new BigDecimal("0.1") 将创建一个 BigDecimal,它正好 等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。3.* 当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。* <p/>* eg:  1.115  用BigDecimal(double) 的构造方法四舍五入,保留2位小数得到的值位 1.11  而BigDecimal(String) 的构造方法四舍五入,保留2位小数得到的值位 1.12* 而且官方的API 也是推荐使用BigDecimal(String)的构造函数。** @param d double类型的字符串* @return 四舍五入后保留2位小数的值*/public static double getRoundHalfUpDouble(double d) {return getRoundHalfUpDouble(String.valueOf(d));}/*** 对于一个double 型的字符串进行四舍五入和保留两位小数处理,如果最后一位小数位为0,则默认不显示** @param doubleString double类型的字符串* @return 四舍五入后保留2位小数的值*/public static double getRoundHalfUpDouble(String doubleString) {try {BigDecimal b = new BigDecimal(doubleString);return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();} catch (Exception e) {return 0.0;}}/*** 对于一个double 型的字符串进行四舍五入和保留两位小数处理,如果最后一位小数位为为0,则仍然显示。** @param doubleString double类型的字符串* @return*/public static String getRoundHalfUpDoubleStr(String doubleString) {try {double tempDoubleString = getRoundHalfUpDouble(doubleString);return String.format("%.2f", tempDoubleString);} catch (Exception e) {return doubleString;}}/*** 精确的double类型的字符串  加法运算** @param doubleStr1 被加数* @param doubleStr2 加数* @return 两个参数的和*/public static double add(String doubleStr1, String doubleStr2) {if (TextUtils.isEmpty(doubleStr1) || TextUtils.isEmpty(doubleStr2)) {return 0;}try {BigDecimal b1 = new BigDecimal(doubleStr1);BigDecimal b2 = new BigDecimal(doubleStr2);return b1.add(b2).doubleValue();} catch (Exception e) {e.printStackTrace();}return 0;}/*** 对double 类型的浮点数进行加法运算** @param v1 被加数* @param v2 加数* @return 两个参数的和*/public static double add(double v1, double v2) {BigDecimal b1 = BigDecimal.valueOf(v1);BigDecimal b2 = BigDecimal.valueOf(v2);return b1.add(b2).doubleValue();}/*** 对double 类型的浮点数进行减法运算。** @param v1 被减数* @param v2 减数* @return 两个参数的差*/public static double subtract(double v1, double v2) {BigDecimal b1 = BigDecimal.valueOf(v1);BigDecimal b2 = BigDecimal.valueOf(v2);return b1.subtract(b2).doubleValue();}/*** 对double 类型的浮点数进行乘法运算。** @param v1 被乘数* @param v2 乘数* @return 两个参数的积*/public static double multiply(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.multiply(b2).doubleValue();}/*** 对double 类型的浮点数进行除法运算。当发生除不尽的情况时,由scale参数指* 定精度,以后的数字四舍五入。** @param v1    被除数* @param v2    除数* @param scale 表示表示需要精确到小数点以后几位。* @return 两个参数的商*/public static double divide(double v1, double v2, int scale) {if (scale < 0) {throw new IllegalArgumentException("The scale must be a positive integer or zero");}BigDecimal b1 = BigDecimal.valueOf(v1);BigDecimal b2 = BigDecimal.valueOf(v2);return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();}}

BigDecial devide方法详解

1、首先说一下用法,BigDecimal中的divide主要就是用来做除法的运算。其中有这么一个方法.

public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode)

第一个参数是除数,第二个参数代表保留几位小数,第三个代表的是使用的模式。

    BigDecimal.ROUND_DOWN:直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2BigDecimal.ROUND_UP:直接进位,比如1.21如果保留1位小数,得到的就是1.3BigDecimal.ROUND_HALF_UP:四舍五入,2.35保留1位,变成2.4BigDecimal.ROUND_HALF_DOWN:四舍五入,2.35保留1位,变成2.3后边两种的区别就是如果保留的位数的后一位如果正好是5的时候,一个舍弃掉,一个进位。

2、BigDecimal.setScale()方法用于格式化小数点

setScale(1)表示保留一位小数,默认用四舍五入方式
setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3
setScale(1,BigDecimal.ROUND_UP)进位处理,2.35变成2.4
setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35变成2.4
setScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入,2.35变成2.3,如果是5则向下舍

android_基础_BigDecimal 更精准的计算相关推荐

  1. 智慧营销 让营销更精准

    目前,企业在其营销活动中使用传统的营销手段常常会面临诸多问题: 营销资源浪费.营销效果低下 随着营销环境越发复杂多样,企业营销成本持续增长 营销欺诈行为使企业获客成本与运营负担加重 智慧营销提供基于手 ...

  2. 计算机视觉怎样实现自我超越?更大规模更精准的数据

    最新发布的<2021中国人工智能应用趋势报告>强调,数据.算力和算法是支撑人工智能发展的"三驾马车",为模型训练提供基本资料的「数据」,是人工智能的根基. 随着互联网. ...

  3. AttoNets,一种新型的更快、更高效边缘计算神经网络

    作者 | Alexander Wong, Zhong Qiu Lin, and Brendan Chwyl 译者 | Rachel 出品 | AI科技大本营(ID:rgznai100) 尽管机器学习已 ...

  4. CVPR2021(Oral) 商汤、港中文实现单目人脸重建新突破: 基于生成网络的渲染器!几何形状更精准!渲染效果更真实!...

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 近日,商汤-港中文联合实验室提出基于风格化对抗生成器的人脸渲染器,用于取代传统图形学基于栅格化的渲染器 ...

  5. 科宇扫地机器人_我的三年16台智能扫地机器人使用回忆录 篇四:扫地谁更精准更干净?新一代3D视讯+激光成像 PK 老式激光扫描,万字实测对比分享...

    我的三年16台智能扫地机器人使用回忆录 篇四:扫地谁更精准更干净?新一代3D视讯+激光成像 PK 老式激光扫描,万字实测对比分享 2019-05-23 11:22:00 37点赞 166收藏 53评论 ...

  6. CVPR2021(Oral) 商汤、港中文实现单目人脸重建新突破: 基于生成网络的渲染器!几何形状更精准!渲染效果更真实!

    近日,商汤-港中文联合实验室提出基于风格化对抗生成器的人脸渲染器,用于取代传统图形学基于栅格化的渲染器来进行3D模型的重建.该方法构建了一种从输入3D模型到生成图像的平滑梯度,同时可以以低精度建模获得 ...

  7. svg大小自适应_网格自适应的 2 种方法——实现更高效的计算

    网格自适应的目标是:修正网格以更有效地解决问题.通常,我们希望使用尽可能少的单元来获得精确的解:并希望在不太重要的区域使用较粗糙的网格,而在感兴趣的区域使用较精细的网格.有时,我们甚至可能会考虑各向异 ...

  8. caffe 人脸关键点检测_人脸检测关键点新增至81个,比Dlib更精准、更贴边

    人脸关键点检测是人脸识别和分析领域中的关键一步,它是诸如自动人脸识别.表情分析.三维人脸重建及三维动画等其它人脸相关问题的前提和突破口. 虽然人脸的结构是确定的,由眉毛.眼睛.鼻子和嘴等部位组成,近似 ...

  9. mysql 复制延迟诊断_新特性解读 | MySQL 8 复制延迟观测新方式,更全面更精准

    转载自公众号:玩转MySQL,作者:洪斌 一直以来 MySQL 复制延迟观测是不完善的,既无法观测到真实的主从延迟,也无法支持复杂的复制拓扑环境,常用的 second_behind_master 指标 ...

最新文章

  1. 推荐三款scrum看板协作工具
  2. git的author和commiter的修改
  3. android中的定时任务一般有两种机制,android 定时任务
  4. 电子书下载:Silverlight 5 in Action
  5. 逆向映射是干嘛的anon_vma, vma, anon_vma_chain
  6. openfeign ribbon 负载_SpringCloud教程(三)声明式访问Feign、负载均衡Ribbon
  7. 【Python】处理UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xa2 in position…
  8. ipv6 ospf配置方法_网络工程师(22):应用最广泛的路由协议OSPF
  9. Android之使用MediaMetadataRetriever类获取视频第一帧
  10. mysql确定数据表中是否存在某字段_MySQL判断表是否存在某个列
  11. 使用github安装atom插件
  12. 怎么对比两个excel文档的数据差异
  13. html动态生成tr标签,JS动态添加tr元素
  14. 电脑出现问题。你的PIN不可用,请单击以重置——解决方案总结
  15. iOS Orientation 屏幕旋转
  16. 基于Spring Boot的讲师积分管理系统(毕业设计,毕设)
  17. 丿玩网站异常监控2012 3月17正式版,个人站长网站管理员必备良器
  18. Matlab运用mapping包在地图上绘制散点图
  19. HBuilder软件下载及安装教程
  20. 学习—吴恩达《机器学习》—手敲代码_准备工作之基于Ubuntu系统的 Anaconda(python环境)搭建

热门文章

  1. 数据结构与算法 25 狄杰斯特拉算法 dijkstra
  2. Problem D. L05-04输出蛇形矩阵
  3. 「THE NEXT」第三届全球小程序生态大会圆满成功,规模空前,爆点不断
  4. 临近毕业招聘季,BOSS直聘依然困在营销里
  5. 基于Android驾校驾考助手 java驾照考试系统
  6. 二手书交易系统设计与实现
  7. centos 温度监控软件
  8. 全球与中国振动监测与诊断系统市场行业供需现状及投资策略分析报告2022-2028年
  9. .s19 文件转换为 .hex 和 .bin文件的方法
  10. 无论小白还是大佬,前端开发必不能少了Ta