BigDecimal常被忽略的问题
一:相除精度丢失的问题
BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题:
问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333......除不尽,这里不能让电脑一直除不尽,所以BigDecimal做出一些限制;
必须按照(数,保留小数位(最好要合理限制最大精度),舍入方式)来操作
否则就会抛出异常,例如:
public static void main(String[] args) { BigDecimal a = new BigDecimal(10);
BigDecimal b = new BigDecimal(3);
BigDecimal c = a.divide(b);
}
执行:抛出
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1616)
二:舍入方式精度丢失的问题
多数相乘时,请勿先进行四舍五入或者其他的方式,以最终计算结果为基础进行取舍精度,虽然一说就明白,但是这一个编码的习惯问题,特别是在金融行业。
舍入方式需要弄明白自己的业务才用,别为了用而随便选一个用
1.ROUND_UP:四舍五入模式从零四舍五入。
public static void main(String[] args) { BigDecimal a = new BigDecimal(0.31);
BigDecimal b = new BigDecimal(3);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_UP);
LOGGER.error("原值:0.1033333...///"+c.toString()+"=0.2"); //结论:0-9都是向前进一位(且当0后还有小数位为前提)
}
2.ROUND_DOWN 四舍五入模式到四舍五入接近零。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(0.39);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_DOWN);
LOGGER.error("原值:0.39///"+c.toString()+"=0.3");
//结论:1-9都是向前进一位
}
3.ROUND_CEILING 四舍五入到正无穷。
public static void main(String[] args) { BigDecimal a = new BigDecimal(0.301);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_CEILING);
LOGGER.error("原值:0.301///"+c.toString()+"=0.4");
//结论:与第一种类似,区别就是舍入到正无穷的范围大,当值为负数时舍入失效,当用第四种解决
}
4.ROUND_FLOOR 四舍五入到负无穷
public static void main(String[] args) { BigDecimal a = new BigDecimal(-0.301);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_FLOOR);
LOGGER.error("原值:0.301///"+c.toString()+"=0.4");
//结论:与上面的正无穷舍入的方式相反,可以互补
}
5.ROUND_HALF_UP 四舍五入方式四舍五入,除非两个邻边距离相等,则四舍五入。
public static void main(String[] args) { BigDecimal a = new BigDecimal(-0.36);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_UP);
LOGGER.error("原值:-0.36///"+c.toString()+"=-0.4");
//结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}
6.ROUND_HALF_DOWN 四舍五入模式四舍五入,除非两个邻边距离相等
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.35);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_DOWN );
LOGGER.error("原值:-0.35///"+c.toString()+"=-0.3");
//结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}
7.ROUND_HALF_EVEN 四舍五入的方式是四舍五入,除非两个邻边是等距的,在这种情况下,四舍五入对甚至邻居。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.35);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_EVEN );
LOGGER.error("原值:-0.35///"+c.toString()+"=-0.3");
//结论:正负数相同,以5为分界,<=5舍掉,>5的进1
}
8.ROUND_UNNECESSARY 舍入模式,以断言所请求的操作具有精确值结果,因此不需要舍入。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(-0.36);
BigDecimal b = new BigDecimal(1);
BigDecimal c = a.divide(b,1,BigDecimal.ROUND_HALF_EVEN );
LOGGER.error("原值:-0.36///"+c.toString()+"=-0.4");
//结论:正负数相同,以5为分界,<=5舍掉,>5的进1
// 断言中使用的,实际开发过程中最好不用
}
三:BigDecimal取值范围的 validation 校验问题总结
常常在与客户端交互时需要做很多校验,在javax.validation下面有很多不错的校验规则
@NotNull :不为空,适用任何地方(@NotBlank只是用字符类型)
@DecimalMax:取得最大值范围
@DecimalMin(value = "0.00", message = "") 取值最小值
三:BigDecimal精度科学计数法问题总结
BigDecimal有一种方法是:stripTrailingZeros(),它提供了去掉小数点后面的多余的0,但是问题是:
public static void main(String[] args) {
BigDecimal A = BigDecimal.valueOf(0.36000).stripTrailingZeros();
BigDecimal B = new BigDecimal(0.36000).stripTrailingZeros();
BigDecimal zeroDecimal = new BigDecimal(0.000).stripTrailingZeros();
System.out.println("原值0.36000//////"+A.toPlainString()+"===0.36");
System.out.println("原值0.36000//////"+B.toPlainString()+"===35999999999999998667732370449812151491641998291015625");
System.out.println("原值0.00000//////"+zeroDecimal+"==0.0000////"+zeroDecimal.toPlainString()+"==0");
}
①:导出是excel会以科学计数法展示数据,如120 -》1.2+E2;
②:如果0.000然后用stripTrailingZeros()是无效的,导出时toPlainString()加上之后就可以了;
③:慎用new BigDecimal();源代码如下;
/**这个构造函数的结果可能有些不可预测。
*可能会假设编写{@code new BigDecimal(0.1)}
* Java创建一个完全等于的{@code BigDecimal}
* 0.1(未缩放值为1,刻度为1),但它是
*实际上等于 *0.1000000000000000055511151231257827021181583404541015*625.
**/ public BigDecimal(double val) {
this(val,MathContext.UNLIMITED);
}
BigDecimal常被忽略的问题的更多相关文章
- JavaScript之parseInt()数值转换常被忽略的问题
使用parseInt()你可以从字符串中获取数值,该方法接受另一个基数参数,这经常省略,但不应该.当字符串以”0″开头的时候就有可能会出问题,例如,部分时间进入表单域,在ECMAScript 3中,开 ...
- [转]关于event的两个常被忽略的api:isDefaultPrevented()和preventDefault()
今天在robert penner(as3 singal的作者)的一篇blog文中顺藤摸瓜到了darron schall的另外一篇blog文(Creating Default, Cancelable E ...
- 小议常被忽略的a标签:visited属性的特殊用法
CSS1/CSS2对于a定义了4个伪类, :link a标签未访问时的样式 :active a标签mousedown时的样式 :hover a标签mouseover时的样式 :visited ...
- 【javascript常见面试题】常见前端面试题及答案
转自:http://www.cnblogs.com/syfwhu/p/4434132.html 前言 本文是在GitHub上看到一个大牛总结的前端常见面试题,很多问题问的都很好,很经典.很有代表性.上 ...
- 说说DOM的那些事儿
引子 先来一颗栗子: <img src="/sub/123.jpg" alt="test" /> <script type="tex ...
- 前端小知识点---html换行被解析为空格的相关知识
这个系列主要记录一下常被忽略但又经常产生影响的知识点,纯做个记录,方便查询 html换行被解析为空格也是常说的3像素空隙的问题,根据测试不同浏览器产生的空隙大小会不一样,Chrome,Firefox, ...
- Top 15 不起眼却有大作用的 .NET功能集
目录 1. ObsoleteAttribute2. 设置默认值属性: DefaultValueAttribute3. DebuggerBrowsableAttribute4. ??运算符5. Curr ...
- 第2章 两种调用JS的方法——在HTML中使用JavaScript
一. <script>标记 第一种方法是把 <sript></script>直接放到head和script两个标记之间(title下面,</head>上 ...
- js中的preventDefault与stopPropagation详解
本篇文章主要是对js中的preventDefault与stopPropagation进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助 首先讲解一下js中preventDefault和stopP ...
随机推荐
- ffmpeg 视频实现各种特效
直接上命令: //渐入i in.mp4 -vf fade=in:0:90 out.mp4 //黑白 i in.mp4 -vf lu ...
- shell编程中的if语句
if语句在任何编程中都是必不可少.至关重要的分支语句,shell也是如此,只不过各种编程中的方式和格式有点不太一样 shell编程中的if语句基本格式如下: if [ X$1 = XA ];then ...
- ubuntu下 远程连接windows服务器工具Remmina
工具不错 https://blog.csdn.net/skykingf/article/details/71539237
- C#容器类,性能介绍
http://www.php.cn/csharp-article-354819.html 1 indexer []声明的变量必须是固定长度的,即长度是静态的:object[] objectArray ...
- Spring Session - 使用Redis存储HttpSession例子
目的 使用Redis存储管理HttpSession: 添加pom.xml 该工程基于Spring Boot,同时我们将使用Spring IO Platform来维护依赖版本号: 引入的依赖有sprin ...
- 3分钟看完Java 8——史上最强Java 8新特性总结之第一篇 函数式编程基础
目录 · 行为参数化 · Lambda表达式 · 概况 · 函数式接口 · 类型推断 · 使用外层变量 · 方法引用 · 复合Lambda表达式 行为参数化 1. 理解函数式编程要先理解行为参数化. ...
- /proc文件系统(二):/proc/<pid>/stat
0. 前言 /proc 文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间. 它以文件系统的方式为内核与进程提供通信的接口.用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某 ...
- [转]Angular 4|5 Material Dialog with Example
本文转自:https://www.techiediaries.com/angular-material-dialogs/ In this tutorial, we're going to learn ...
- [转]npm、 cnpm、yarn
本文转自:https://blog.csdn.net/sinat_34682450/article/details/79473658 终于搞懂了三者之间的关系- 要知道三者之间的关系首先要了解三个包管 ...
- SQL 查看表每一个列的名字以及类型
select a.name,b.name from sys.columns as a join sys.types as b on a.system_type_id=b.system_type_id ...