一、问题的提出:

如果我们编译运行下面这个程序会看到什么?
public class Test{
    public static void main(String args[]){
        System.out.println(0.05+0.01);
        System.out.println(1.0-0.42);
        System.out.println(4.015*100);
        System.out.println(123.3/100);
    }
};
你没有看错!结果确实是
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
Java中的简单浮点数类型float和double不能够进行运算。不光是Java,在其它很多编程语言中也有这样的问题。在大多数情况下,计算的结果是准确的,但是多试几次(可以做一个循环)就可以试出类似上面的错误。现在终于理解为什么要有BCD码了。
这个问题相当严重,如果你有9.999999999999元,你的计算机是不会认为你可以购买10元的商品的。
在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。现在让我们看看如何解决这个问题。
 
四舍五入
我们的第一个反应是做四舍五入。Math类中的round方法不能设置保留几位小数,我们只能象这样(保留两位):
public double round(double value){
    return Math.round(value*100)/100.0;
}
非常不幸,上面的代码并不能正常工作,给这个方法传入4.015它将返回4.01而不是4.02,如我们在上面看到的
4.015*100=401.49999999999994
因此如果我们要做到精确的四舍五入,不能利用简单类型做任何运算
java.text.DecimalFormat也不能解决这个问题:
System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
输出是4.02

二、精确计算

在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal

我们如果需要精确计算,非要用String来够造BigDecimal不可!在《Effective Java》一书中的例子是用String来够造BigDecimal的

下面提供计算的代码:

(注意:divide方法中推荐使用枚举RoundingMode.HALF_UP)

 package com.wetalk.wbs.bas.util;

 import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode; /**
* double的计算不精确,会有类似0.0000000000000002的误差,正确的方法是使用BigDecimal或者用整型
* 整型地方法适合于货币精度已知的情况,比如12.11+1.10转成1211+110计算,最后再/100即可
* 以下是摘抄的BigDecimal方法:
*/
public class DoubleUtil implements Serializable {
private static final long serialVersionUID = -3345205828566485102L;
// 默认除法运算精度
private static final Integer DEF_DIV_SCALE = 2; /**
* 提供精确的加法运算。
*
* @param value1 被加数
* @param value2 加数
* @return 两个参数的和
*/
public static Double add(Double value1, Double value2) {
BigDecimal b1 = new BigDecimal(Double.toString(value1));
BigDecimal b2 = new BigDecimal(Double.toString(value2));
return b1.add(b2).doubleValue();
} /**
* 提供精确的减法运算。
*
* @param value1 被减数
* @param value2 减数
* @return 两个参数的差
*/
public static double sub(Double value1, Double value2) {
BigDecimal b1 = new BigDecimal(Double.toString(value1));
BigDecimal b2 = new BigDecimal(Double.toString(value2));
return b1.subtract(b2).doubleValue();
} /**
* 提供精确的乘法运算。
*
* @param value1 被乘数
* @param value2 乘数
* @return 两个参数的积
*/
public static Double mul(Double value1, Double value2) {
BigDecimal b1 = new BigDecimal(Double.toString(value1));
BigDecimal b2 = new BigDecimal(Double.toString(value2));
return b1.multiply(b2).doubleValue();
} /**
* 提供(相对)精确的除法运算,当发生除不尽的情况时, 精确到小数点以后10位,以后的数字四舍五入。
*
* @param dividend 被除数
* @param divisor 除数
* @return 两个参数的商
*/
public static Double divide(Double dividend, Double divisor) {
return divide(dividend, divisor, DEF_DIV_SCALE);
} /**
* 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
*
* @param dividend 被除数
* @param divisor 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static Double divide(Double dividend, Double divisor, Integer scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(dividend));
BigDecimal b2 = new BigDecimal(Double.toString(divisor));
return b1.divide(b2, scale,RoundingMode.HALF_UP).doubleValue();
} /**
* 提供指定数值的(精确)小数位四舍五入处理。
*
* @param value 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double value,int scale){
if(scale<0){
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(value));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale, RoundingMode.HALF_UP).doubleValue();
}
}

Java中的Double类型计算的更多相关文章

  1. JAVA中使用浮点数类型计算时,计算精度的问题

    标题     在Java中实现浮点数的精确计算    AYellow(原作) 修改    关键字     Java 浮点数 精确计算   问题的提出:如果我们编译运行下面这个程序会看到什么?publi ...

  2. MySql数据库类型bit等与JAVA中的对应类型【布尔类型怎么存】

    用char(1):可以表示字符或者数字,但是不能直接计算同列的值.存储消耗1个字节 用tinyint:只能表示数字,可以直接计算,存储消耗2个字节 用bit: 只能表示0或1,不能计算,存储消耗小于等 ...

  3. Java中的Bigdecimal类型运算

    Java中的Bigdecimal类型运算 双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数进行运算和处理.Java在java.math包中提 供的API类BigD ...

  4. 详解java中的byte类型

    Java也提供了一个byte数据类型,并且是基本类型.java byte是做为最小的数字来处理的,因此它的值域被定义为-128~127,也就是signed byte.下面这篇文章主要给大家介绍了关于j ...

  5. 深入理解java中的byte类型

    作者 | 进击的石头--GO! 来源 | https://www.cnblogs.com/zl181015/p/9435035.html#4432849 Java也提供了一个byte数据类型,并且是基 ...

  6. java中的null类型---有关null的9件事

    摘自 https://blog.csdn.net/qq_25077777/article/details/80174763 今天听到一个问题,java中的null类型,null竟然是一种类型 java ...

  7. 理解Java中的字符串类型

    1.Java内置对字符串的支持: 所谓的内置支持,即不用像C语言通过char指针实现字符串类型,并且Java的字符串编码是符合Unicode编码标准,这也意味着不用像C++那样通过使用string和w ...

  8. Java中的枚举类型详解

    枚举类型介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常量的定义 ...

  9. 关于java中的事件类型

    java中的Date是为了证明:天才的程序员也会犯错: java中的Calendar是为了证明:普通的程序员也会犯错. ———————————————————— stackoverflow上大部分都推 ...

随机推荐

  1. python-django 模型model字段类型说明

    V=models.CharField(max_length=None<, **options>) #varchar V=models.EmailField(<max_length=7 ...

  2. Python学习笔记-Day3-python关键字

    1.and 逻辑与 2.assert 判断某个条件是否为真,如果为假,抛出错误 3.break跳出for,while循环 4.class 类定义 5.continue 跳出本次循环,执行下次循环 6. ...

  3. Poj(2771),最大独立集

    题目链接:http://poj.org/problem?id=2771 Guardian of Decency Time Limit: 3000MS   Memory Limit: 65536K To ...

  4. winform中拖动功能实现技巧

    实现的需求,我通过拖动选中的用户行放到左边的机构节点上,从而实现用户改变组织机构的关系 贴代码 private DataGridViewSelectedRowCollection sourceRowC ...

  5. request、response 中文乱码问题与解决方式

    request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码:   response乱码指的是:服务器向浏览器发送的数据包含中文字符,浏览器中显示的是乱码: ...

  6. hnu Counting ones 统计1-n 二进制中1的个数

    Counting ones Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:65536KB Total submit users ...

  7. 在VS中编译C++静态库以及使用的方法

    1.编译静态库 // add.h #pragma once class Add { public: Add(void); ~Add(void); int add(int a,int b); }; #i ...

  8. 如何在安装32位Oracle客户端组件的情况下以64位模式运行

    C#使用System.Data.OracleClient连接Oracle数据库.之前在WinXP上正常运行的程序移植到Windows 2008 x64上之后就连不上数据库了,错误信息如下:启动data ...

  9. 高通APQ8074 spi 接口配置

    高通APQ8074 spi 接口配置 8074 平台含有两个BLSP(BAM Low-Speed Peripheral) , 每一个BLSP含有两个QUP, 每一个QUP可以被配置为I2C, SPI, ...

  10. 我的android学习经历23

    学习fragment时遇到的问题 这几天学习fragment静态加载时遇到这样的问题: java.lang.RuntimeException: Unable to start activity Com ...