一、问题的提出:

如果我们编译运行下面这个程序会看到什么?
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. 关于IllegalMonitorStateException异常

    关于IllegalMonitorStateException异常: api中的解释  另请参见: Object.notify(), Object.notifyAll(), Object.wait(), ...

  2. 编译ITK

    [2016年7月4周]编译ITK 1.下载必备文件 InsightToolkit-4.8.1.cmake 2.cmake编译 修改CMAKE_INSTALL_PREFIX配置到需要生成的目录下面去. ...

  3. python 数据加密以及生成token和token验证

    代码如下: # -*- coding: utf-8 -*- from passlib.apps import custom_app_context as pwd_context import conf ...

  4. git status message - Your branch is ahead of origin/master by X commits

    git reset --hard origin/master git status FAQ: When I issue the "git status" command, I se ...

  5. 华东交通大学2016年ACM“双基”程序设计竞赛 1007

    Problem Description ACM小学妹在今天的暑假训练结束后,想看球赛放松一下.当他打开电脑时查询到联盟今天直播N场球赛,每场球赛的起止时间(S1,E1),(S2,E2),...,(SN ...

  6. 在Visual Studio中使用MonoTouch开发iOS应用程序

    前段时间在工作机上装了Mac OS X,这主要是因为我最近需要开发iPhone应用程序.虽然Xcode,Objective C一定是开发iOS应用程序的主流,但是经过一番考虑,我还是决定尝试一下使用M ...

  7. duilib\utils\utils.h(251) : error C2504: “VARIANT”: 未定义基类

    转载:http://blog.csdn.net/SP_daiyq/article/details/44542939?locationNum=3 创建win32应用程序的工程文件,删除不需要的代码,只留 ...

  8. 使用VS2010开发Qt程序的一点经验(转载)

    转载:http://www.cnblogs.com/csuftzzk/p/VS_Qt_Experience.html 导读 相比于Qt Creator,我更喜欢用VS2010来进行开发.虽然启动时间相 ...

  9. baidu 快递查询API

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  10. Cheatsheet: 2013 09.01 ~ 09.09

    .NET Multi Threaded WebScraping in CSharpDotNetTech .NET Asynchronous Patterns An Overview of Projec ...