java double数据类型运算问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java double数据类型运算问题相关的知识,希望对你有一定的参考价值。

double a = 5.0;
double b = 0.1;

double c = 0.1;

System.out.println(a+b+c); //为什么结果是5.199999999999999,不应该是5.200000000000000吗?

使用Java,double 进行运算时,经常出现精度丢失的问题,总是在一个正确的结果左右偏0.0000**1。
特别在实际项目中,通过一个公式校验该值是否大于0,如果大于0我们会做一件事情,小于0我们又处理其他事情。
这样的情况通过double计算出来的结果去和0比较大小,尤其是有小数点的时候,经常会因为精度丢失而导致程序处理流程出错。
所以一般对double类型进行运算时,做好对结果进行处理,然后拿这个值去做其他事情。

目前总结如下:

/**

* 对double数据进行取精度.

* @param value double数据.

* @param scale 精度位数(保留的小数位数).

* @param roundingMode 精度取值方式.

* @return 精度计算后的数据.

*/

public static double round(double value, int scale,

int roundingMode)

BigDecimal bd = new BigDecimal(value);

bd = bd.setScale(scale, roundingMode);

double d = bd.doubleValue();

bd = null;

return d;



/**
* double 相加
* @param d1
* @param d2
* @return
*/
public double sum(double d1,double d2)
BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
return bd1.add(bd2).doubleValue();


/**
* double 相减
* @param d1
* @param d2
* @return
*/
public double sub(double d1,double d2)
BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
return bd1.subtract(bd2).doubleValue();


/**
* double 乘法
* @param d1
* @param d2
* @return
*/
public double mul(double d1,double d2)
BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
return bd1.multiply(bd2).doubleValue();


/**
* double 除法
* @param d1
* @param d2
* @param scale 四舍五入 小数点位数
* @return
*/
public double div(double d1,double d2,int scale)
// 当然在此之前,你要判断分母是否为0,

// 为0你可以根据实际需求做相应的处理

BigDecimal bd1 = new BigDecimal(Double.toString(d1));
BigDecimal bd2 = new BigDecimal(Double.toString(d2));
return bd1.divide

(bd2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();


这样,计算double类型的数据计算问题就可以处理了。
另外补充一下 javascript 四舍五入的方法:
小数点问题

Math.round(totalAmount*100)/100 (保留 2 位)

function formatFloat(src, pos)

return Math.round(src*Math.pow(10, pos))/Math.pow(10, pos);
参考技术A 浮点数值没办法用十进制来精确表示的原因要归咎于CPU表示浮点数的方法。这样的话您就可能会牺牲一些精度,有些浮点数运算也会引入误差。以上面提到的情况为例,2.4的二进制表示并非就是精确的2.4。反而最为接近的二进制表示是 2.3999999999999999。原因在于浮点数由两部分组成:指数和尾数。浮点数的值实际上是由一个特定的数学公式计算得到的。您所遇到的精度损失会在任何操作系统和编程环境中遇到。float类型的变量只有7位的精度,而double类型的变量有15位的精度 参考技术B 使用Java,double 进行运算时,经常出现精度丢失的问题,总是在一个正确的结果左右偏0.0000**1。 特别在实际项目中,通过一个公式校验该值是否大于0,如果大于0我们会做一件事情,小于0我们又处理其他事情。 这样的情况通过double计算出来的结果去和0比较大小,尤其是有小数点的时候,经常会因为精度丢失而导致程序处理流程出错。

解决方法有:
//方法一
NumberFormat nFormat=NumberFormat.getNumberInstance();
nFormat.setMaximumFractionDigits(2);//设置小数点后面位数为
System.out.println(nFormat.format(3.1415););
/*
方法二
double d = 14.7155;
DecimalFormat df0 = new DecimalFormat("###");
DecimalFormat df1 = new DecimalFormat("###.0");
DecimalFormat df2 = new DecimalFormat("###.00");
System.out.println(df0.format(d));
System.out.println(df1.format(d));
System.out.println(df2.format(d));
double test = Math.round(d);
System.out.println(test);
*/
参考技术C 这个就是double的精度问题啊?
java.math.BigDecimal

double n=0.01;
double m=0.06;
java.math.BigDecimal d1=new java.math.BigDecimal(String.valueOf(n));
java.math.BigDecimal d2=new java.math.BigDecimal(String.valueOf(m));

System.out.println(d1.add(d2).doubleValue());

关于Java中double类型的运算精度问题

(其工具类在项目中的ArithUtil

原文网址:http://blog.csdn.net/pttaag/article/details/5912171

先上个案例:

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中的简单浮点数类型floatdouble不能够进行运算。
这个问题相当严重,如果你有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

 

现在我们已经可以解决这个问题了,原则是使用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)

以下是该工具类源码,其实就是将繁琐的过程进行封装,便于直接调用:

import java.math.BigDecimal;
/**
 * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精
 * 确的浮点数运算,包括加减乘除和四舍五入。
 */
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();
    }
    /**
     * 提供精确的减法运算。
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    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();
    } 
    /**
     * 提供精确的乘法运算。
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    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();
    }
 
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * 小数点以后10位,以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1,double v2){
        return div(v1,v2,DEF_DIV_SCALE);
    }
 
    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    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();
    }
 
    /**
     * 提供精确的小数位四舍五入处理。
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    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数据类型运算问题的主要内容,如果未能解决你的问题,请参考以下文章

Java的基本数据类型与运算符

java数据类型转换

c语言 不同数据类型间的混合运算

JAVA数据类型,变量,转换,常量,运算符

java基础再回首————数据类型和运算符

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