在刚刚做完的一个项目中,遇到了double型计算不精确的问题。到网上查找后,问题得到解决。经验共享,在这里总结一下。

Java中的浮点数类型float和double不能够进行精确运算。这个问题有时候非常严重。比如,经过double型直接计算,1.4×1.5有时会得出2.0999999999999996的结果,但实际上,应该得到2.10。而且,类似的情况并不仅限于乘法计算。

在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。所以,在商业计算中我们要用:java.math.BigDecimal

BigDecimal一共有4个构造方法,其中不属于int的有两个,它们是:

1、BigDecimal(double val)

Translates a double into a BigDecimal.

2、BigDecimal(String val)

Translates the String repre sentation of a BigDecimal into a BigDecimal.

上面的API简要描述相当的明确,而且通常情况下,上面的那一个使用起来要方便一些。但是,第一个构造方法的详细说明中有:

Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.

The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.

所以,如果需要精确计算,非要用String来构造BigDecimal不可。

一、解决方案:

现在已经可以解决这个问题了,原则是使用BigDecimal并且一定要用String来构造。

但是想像一下吧,如果要做一个加法运算,需要先将两个浮点数转为String,然后构造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。没错,这样太繁琐了。

下面的工具类Arith可以简化这部分操作。它提供以下静态方法,包括加减乘除和四舍五入:

public static double add(double v1,double v2)

    public static double sub(double v1,double v2)

    public static double mul(double v1,double v2)

    public static double div(double v1,double v2)

    public static double div(double v1,double v2,int scale)

    public static double round(double v,int scale)

◆源文件Arith.java:

import java.math.BigDecimal;
    public class
Arith{
       
//默认除法运算精度
       
private static final int DEF_DIV_SCALE = 10;
       
//这个类不能实例化
       
private Arith(){

}
   
/**

* 提供精确的加法运算。

* @param v1 被加数

* @param v2 加数

* @return 两个参数的和

*/

public static double add(double v1,double v2){

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

return b1.add(b2).doubleValue();

}

public static double sub(double v1,double v2){

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

return b1.subtract(b2).doubleValue();

}

public
static double mul(double v1,double v2){

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

return b1.multiply(b2).doubleValue();

}

public
static double div(double v1,double v2){

return div(v1,v2,DEF_DIV_SCALE);

}

/**

*
提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指

* 定精度,以后的数字四舍五入。
    
*/

public
static double div(double v1,double v2,int scale){

if(scale<0){

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

return
b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();

}

public
static double round(double v,int scale){

if(scale<0){

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b = new BigDecimal(Double.toString(v));

BigDecimal one = new BigDecimal("1");

return
b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();

}

}

Java中的浮点型(Double&Float)计算问题的更多相关文章

  1. Java中long和double的原子性

    Java中long和double的原子性 java中基本类型中,long和double的长度都是8个字节,32位(4字节)处理器对其读写操作无法一次完成,那么,JVM,long和double是原子性的 ...

  2. Java中String转换Double类型 Java小数点后留两位

    Java中String转换Double类型 double num1 = 0.0; String qq = "19.987"; num1 = Double.valueOf(qq.to ...

  3. 在JAVA中怎么比较Double类型数据的大小

    在JAVA中怎么比较Double类型数据的大小  我来答  浏览 33044 次   3个回答 #活动# “双11”答题活动,奖励加码!最高得2000元购物礼金! pollutedair 2015- ...

  4. java中的浮点(float)运算

    一.  关于浮点运算,需要说明的几点: 1.  在java中,进行浮点运算并不会处理例外情况,所以,即使除数为0,也不会有例外被抛出; 2.  当运算结果是溢出(Infinity)时,结果为Infin ...

  5. java中如果需要精确的计算答案,请避免使用double类型与float类型

    double类型与float类型主要用于科学计算与工程计算而设计的,用于二进制浮点计算.对于普通计算通常是结果不准确的,所以对于普通的浮点数的加减法等,解决的方法需要用int,long,BigDeci ...

  6. Java中如何解决double和float精度不准的问题

    我们知道浮点数是无法在计算机中准确表示的,例如0.1在计算机中只是表示成了一个近似值,因此,对付点数的运算时结果具有不可预知性. 在进行数字运算时,如果有double或float类型的浮点数参与计算, ...

  7. java中对于浮点型数据操作

    java的基本数据类型-浮点型:单精度(float)和双精度(double). float:单精度浮点数在机内占4个字节.有效数字8位.表示范围:-3.40E+38 ~ +3.40E+38; doub ...

  8. java中四种阶乘的计算

    package com.zf.s2;//创建一个包   import java.math.BigInteger;//导入类 import java.util.ArrayList; import jav ...

  9. Java中比较不同的MD5计算方式

    在项目中经常需要使用计算文件的md5,用作一些用途,md5计算算法,通常在网络上查询时,一般给的算法是读取整个文件的字节流,然后计算文件的md5,这种方式当文件较大,且有很大并发量时,则可能导致内存打 ...

随机推荐

  1. MySQL(十二)游标和触发器

    一.游标 定义:存储在MySQL服务器上的数据库查询,是一种被select语句检索出来的结果集. 作用:方便在检索出来的结果集中前进或后退一行或多行. 游标主要用于交互式应用:MySQL中的游标只能用 ...

  2. 5、数组&字符串&结构体&共用体&枚举

    程序中内存从哪里来 三种内存来源:栈(stack).堆(heap).数据区(.date): 栈(stack) 运行自动分配.自动回收,不需要程序员手工干预: 栈内存可以反复使用: 栈反复使用后,程序不 ...

  3. 你要的fpga&数字前端笔面试题都在这儿了

    转自http://ninghechuan.com 你要的FPGA&数字前端笔面试题来了 FPGA&ASIC基本开发流程 题目:简述ASIC设计流程,并列举出各部分用到的工具. 勘误:C ...

  4. GATT服务搜索流程(二)

    关于bta_dm_cb.p_sec_cback,这里我们之前已经分析过,他就是bte_dm_evt ,最终调用的函数btif_dm_upstreams_evt : static void btif_d ...

  5. JVM规范系列第1章:引言

    如果你还没下载<Java虚拟机规范>这本书,那么先点击这里下载再一块儿看吧. 前言 Java 虚拟机是一个抽象化的机器,整个规范中提及的 Java 虚拟机都是抽象化的概念,而不是特指 Or ...

  6. Jmeter(三十三)_JsonPath表达式提取响应

    我们在用jmeter做接口测试的时候,有的时候会遇到一些复杂的json响应.比如多层list嵌套时的取值 一个简单的例子: $..Name:列出所有省份 $..Province[0].Name 提取P ...

  7. oracle如何导出和导入数据库/表

    oracle如何导出和导入数据库/表 oracle如何将项目中的表导出后在导入自己的数据库中,这是一个完整的操作,对于数据库备份或在本地查看数据验证数据进场用到,一般情况下我都用dos黑窗口进行操作, ...

  8. vue element-ui 动态上传

    上传填写完毕的幼儿及体测数据文件,上传成功后会自动导入该文件的数据 <el-upload :action="UploadUrl()" :on-success="Up ...

  9. Segment Occurrences(string find函数)

    Description You are given two strings s and t, both consisting only of lowercase Latin letters.The s ...

  10. 分页查询信息(使用jdbc连接mysql数据库实现分页查询任务)

             分页查询信息       使用jdbc连接mysql数据库实现分页查询任务 通过mysql数据库提供的分页机制,实现商品信息的分页查询功能,将查询到的信息显示到jsp页面上. 本项目 ...