Java中BigDecimal,DateFormatter 和迭代器的"陷阱"

前言:

使用 IDEA 创建一个 Maven 项目 calculate-date-traps 并导入 Junit 依赖。

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

在进行计费时使用 Double 和 Float 类型计算经常会出现丢失精度的情况,在 test 包下新建一个测试类 ScaleLostTest。

public class ScaleLostTest {

    @Test
    public void testDoubleLostScale(){
        double alpha = 1;
        double bravo = 20.2;
        double charlie = 400.03;
        System.out.println(alpha + bravo + charlie);
    }
}

执行上述代码,输出结果如下 :

使用 Double 类型进行精确运算出现了精度问题。

代码中所使用的这些数最终都会转换成二进制,而浮点类型的数转换成二进制并不是精确地二进制,只能是最接近的二进制,这是应为浮点数是由指数和尾数两部分组成,所以在浮点数计算的过程中会出现丢失精度的问题。

如果恰巧计算结果的二进制能和十进制准确转换那么自然也就不会出现丢失精度的问题了。浮点数并不适合进行精确计算而更适合科学计算。而 BigDecimal 类型的核心就是精度,在 test 包下新建一个测试类 BigDecimalTest

public class BigDecimalTest {

    @Test
    public void testScaleException(){
        BigDecimal bigDecimal = new BigDecimal("12138.121");
        BigDecimal res = bigDecimal.setScale(2);
        System.out.println(res);
    }
}

执行上述代码,输出结果如下: 

设置的精度既小数点的位数比原来小会报错。设置为5,会自动补上0,再次执行测试输出结果如下:

只想保留两位数字,如何解决?如何对原始数字进行舍入?BigDecimal支持的舍入方式有很多中,向上取整,向下取整,四舍五入等

@Test
public void testChangeScale(){
    BigDecimal bigDecimal = new BigDecimal("12138.121");
    BigDecimal res = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
    System.out.println(res);
}

12138.128

测试其他舍入方式,除法运算,除不尽出现异常问题,除不尽,既无限循环的问题

@Test
public void testDivideException(){
    BigDecimal d1 = new BigDecimal(10);
    BigDecimal d2 = new BigDecimal(3);
    System.out.println(d1.divide(d2));
}

@Test
public void testSolveDivideException(){
    BigDecimal d1 = new BigDecimal(10);
    BigDecimal d2 = new BigDecimal(3);
    System.out.println(d1.divide(d2, 2, BigDecimal.ROUND_HALF_UP));
}

指定精度和舍入方式

总结:使用BigDecimal一定要指定保留小数点的位数和指定的舍入方式

精度问题导致结果比较不一致:

@Test
public void testCompare(){
    BigDecimal d1 = new BigDecimal("0");
    BigDecimal d2 = new BigDecimal("0.0");

    System.out.println(d1.equals(d2));
    System.out.println(d1.compareTo(d2));
}

equals()方法,精度不同直接返回false

到此这篇关于Java中BigDecimal,DateFormatter 和迭代器的"陷阱"的文章就介绍到这了,更多相关java 迭代器陷阱内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中BigDecimal的舍入模式解析(RoundingMode)

    目录 BigDecimal的舍入模式(RoundingMode) BigDecimal的常规用法 BigDecimal的舍入模式(RoundingMode) BigDecimal.divide方法中必须设置roundingMode,不然会报错. ROUND_UP:向正无穷方向对齐(转换为正无穷方向最接近的所需数值) ROUND_DOWN:向负无穷方向对齐 ROUND_CEILING:向原点的反方向对齐 ROUND_FLOOR:向原点方向对齐 ROUND_HALF_UP:“四舍五入”,如果舍弃部分

  • java中BigDecimal用法详解

    首先,学习一个东西,我们都必须要带着问题去学,这边我分为 [为什么?][是什么?][怎么用?] [为什么要用BigDecimal?] 首先,我们先看一下,下面这个现象 那为什么会出现这种情况呢? 因为不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度. 注:根本原因是:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确.只能无限接近于那个值 但是,在项目中,我们不可能让这种情况出现,特别是金融项目,因为涉及金额的计算都必须十分精确

  • SpringBoot解决BigDecimal传到前端后精度丢失问题

    目录 简介 问题描述 实例 问题复现 Java后端BigDecimal的范围 解决方案 方案1:全局处理 方案2:局部处理 简介 本文用示例介绍SpringBoot如何解决BigDecimal传到前端后精度丢失问题. 问题描述 实例 Controller package com.knife.controller; import com.knife.entity.UserVO; import org.springframework.web.bind.annotation.GetMapping; i

  • 使用BigDecimal除法后保留两位小数

    目录 BigDecimal除法后保留两位小数 详细描述 BigDecimal除法异常Non-terminating decimal expansion 异常分析 解决措施 思考 总结 BigDecimal除法后保留两位小数 BigDecimal numBigDecimal=new BigDecimal(5.33); numBigDecimal=ConvertNumber(numBigDecimal,3,2);//调用,5.33/3后保留两位小数1.7766666=1.78 //BigDecima

  • BigDecimal divide除法除不尽报错的问题及解决

    目录 BigDecimal divide除法除不尽报错 解决办法 关于BigDecimal除法问题 BigDecimal做除法时 BigDecimal源码 BigDecimal divide除法除不尽报错 用BigDecimal做除法的时候,直接拿起两数怼上除法有时候会出现除不尽就会报错 列如: BigDecimal a = new BigDecimal(10); BigDecimal re = a.divide(new BigDecimal(3)); System.out.println(re

  • Java你不了解的大数型BigInteger与BigDecimal类

    BigInteger类 在Java当中,是有许多数字要进行处理的类,比如Integer类,但是Integer类它也是有上限的.它的最大值就是到2^31-1. 如果我们此时想要表示更大的数,那就用Integer是无法表示的了,所在在Java当中提供了BigInteger类. BigInteger类支持的数字可以说是无限大的,且支持任意精度的整数,也就是说他可以准确的表示任意数值而不会产生丢失的. 在这里也强调一下,因为传入的数型是字符型,所以在做运算的时候,不能使用 + - * / 对应的就是使用

  • Java中BigDecimal,DateFormatter 和迭代器的"陷阱"

    前言: 使用 IDEA 创建一个 Maven 项目 calculate-date-traps 并导入 Junit 依赖. <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> 在进行计费时使

  • Java中BigDecimal的基本运算(详解)

    BigDecimal一共有4个够造方法,让来看看其中比较常用的两种用法: 第一种:BigDecimal(double val) Translates a double into a BigDecimal. 第二种:BigDecimal(String val) Translates the String repre sentation of a BigDecimal into a BigDecimal. 使用BigDecimal要用String来够造,要做一个加法运算,需要先将两个浮点数转为Str

  • 浅谈java中BigDecimal的equals与compareTo的区别

    这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等). [注:以下所讲都是以sun jdk 1.4.2版本为例,其他版本实现未必一致,请忽略] 首先看一下BigDecimal的equals方法: public boolean equals(Object x){ if (!(x instanceof BigDecimal)) return false; BigDecima

  • Java中BigDecimal类的简单用法

    本文实例讲述了Java中BigDecimal类的简单用法,是Java程序设计中非常实用的技巧,分享给大家供大家参考.具体用法分析如下: 一般来说,一提到Java里面的商业计算,我们都知道不能用float和double,因为他们无法进行精确计算.但是Java的设计者给编程人员提供了一个很有用的类BigDecimal,他可以完善float和double类无法进行精确计算的缺憾.BigDecimal类位于java.maths类包下.首先我们来看下如何构造一个BigDecimal对象.它的构造函数很多,

  • java中BigDecimal的操作方法

    本文实例讲述了java中BigDecimal的操作方法.分享给大家供大家参考.具体分析如下: 由于double,float的精度不够,因此在进行商业计算的时候要使用的BigDecimal.BigDecimal对象创建如下: 复制代码 代码如下: BigDecimal b = new BigDecimal("12.000001"); System.out.println(b); 输出结果为:12.000001: BigDecimal在创建的时候可以传入String和double,但是最好

  • 详谈Java中BigDecimal的一个除法异常

    如下所示: java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 说明遇到除不尽的情况了,需要指定商的小数精度和舍入模式. 比如: a=b.divide(c,2,RoundingMode.HALF_UP); 以上这篇详谈Java中BigDecimal的一个除法异常就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • Java中BigDecimal精度和相等比较的坑

    为什么要有BigDecimal ,他是干什么的 float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,这时候就要使用BigDecimal啦. 什么是BigDecimal BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成.如果为零或正数,则标度是小数点后的

  • 浅谈java中BigDecimal类的简单用法

    一.BigDecimal概述 ​ Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理.一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度.所以开发中,如果我们需要精确计算的结果,则必须使用

  • Java中BigDecimal类的使用详解

    不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度.Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.BigDecimal所创建的是对象,我们不能使用传统的+.-.*./等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法.方法中的参数也必须是BigDecimal的对象.构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象. 一.BigDecimal转换取Double数据 假设我

  • java中BigDecimal和0比较的示例代码

    BigDecimal 和 0 比较大小 调用BigDecimal中的compareTo方法, 如: int i = bigDecimal.compareTo(BigDecimal.Zero); i=0:表示bigDecimal的值  等于 0 i=1:表示bigDecimal的值与 大于0 i=-1:表示bigDecimal的值与 小于 0 参考案例 BigDecimal num= new BigDecimal("18"); int i=num.compareTo(BigDecimal

随机推荐