`
greenwen
  • 浏览: 216749 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Double与BigDecimal 精度问题

    博客分类:
  • java
阅读更多
[1] 精确的浮点运算:
在Java里面,有时候为了保证数值的准确性需要精确的数据,先提供一个例子就可以发现问题了:
public class FloatNumberTester {
    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

这样的话这个问题就相对严重了,如果我们使用123.3元交易,计算机却因为1.2329999999999999而拒绝了交易,岂不是和实际情况大相径庭。

[2] 四舍五入:
另外的一个计算问题,就是四舍五入。但是Java的计算本身是不能够支持四舍五入的,比如:
public class GetThrowTester {
    public static void main(String args[]){
        System.out.println(4.015 * 100.0);
    }
}
 
这个输出为:
401.49999999999994
所以就会发现这种情况并不能保证四舍五入,如果要四舍五入,只有一种方法
java.text.DecimalFormat:
import java.text.DecimalFormat;
public class NumberFormatMain {
    public static void main(String args[]){
        System.out.println(new DecimalFormat("0.00").format(4.025));
        System.out.println(new DecimalFormat("0.00").format(4.024));
    }
}

上边代码输出为:
4.02 
4.02 

发现问题了么?因为DecimalFormat使用的舍入模式, 舍入模式 详情参见本文最后部分。
[3] 浮点输出:
  Java浮点类型数值在大于9999999.0就自动转化成为科学计数法,看看下边的例子:
 
public class FloatCounter {
    public static void main(String args[]){
        System.out.println(9969999999.04);
        System.out.println(199999999.04);
        System.out.println(1000000011.01);
        System.out.println(9999999.04);
    }
}

输出结果为:
 
9.96999999904E9 
1.9999999904E8 
1.00000001101E9 
9999999.04
 

但是有时候我们不需要科学计数法,而是转换成为字符串,所以这样可能会有点麻烦。
总结:
所以在项目当中,对于浮点类型以及大整数的运算 还是尽量不要用double,long等基本数据类型以及其包装类,还是用Java中提供的BigDecimal,BigInteger等大数值类型来代替吧。
但这里特别说明一下BigDecimal类的两个构造函数的区别,他们分别是:
new BigDecimal(String  val ) 和 new BigDecimal(double  val )
先看例子:
public class BigDecimalMain {
    public static void main(String args[]){
        System.out.println(new BigDecimal(123456789.01).toString());
        System.out.println(new BigDecimal("123456789.01").toString());
    }
}

输出结果有一次令人意外了,同时两者之间的区别也一目了然了:
123456789.01000000536441802978515625 
123456789.01 

所以在 就是想利用double原始类型进行了相关计算之后再转成BigDecimal类型 的场合下,为了防止精度出现偏离,建议使用参数为String类型的该构造方法。即new BigDecimal(String  val )。


BigDecimal舍入模式介绍:
  舍入模式在java.math.RoundingMode 里面:
RoundingMode.CEILING :向正无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于 RoundingMode.UP;如果结果为负,则舍入行为类似于 RoundingMode.DOWN。注意,此舍入模式始终不会减少计算值
 
输入数字 使用CEILING舍入模式将数字舍入为一位数 
5.5
2.5
1.1
1.0
-1.0 -1 
-1.1 -1 
-1.6 -1 
-2.5 -2
-5.5 -5

RoundingMode.DOWN :向零方向舍入的舍入模式。从不对舍弃部分前面的数字加 1(即截尾)。注意,此舍入模式始终不会增加计算值的绝对值
输入数字 使用DOWN舍入模式将数字舍入为一位数 
5.5
2.5
1.1
-1.0 -1 
-1.6 -1 
-2.5 -2 
-5.5 -5 

RoundingMode.FLOOR :向负无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于 RoundingMode.DOWN;如果结果为负,则舍入行为类似于 RoundingMode.UP。注意,此舍入模式始终不会增加计算值 
输入数字 使用FLOOR舍入模式将输入数字舍入为一位 
5.5
2.3
1.6
1.0
-1.1 -2 
-2.5 -3 
-5.5 -6


RoundingMode.HALF_DOWN :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。如果被舍弃部分 > 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN  
输入数字 使用HALF_DOWN输入模式舍入为一位 
5.5
2.5
1.6
1.0
-1.1 -1 
-1.6 -2 
-2.5 -2 
-5.5 -5 

RoundingMode.HALF_EVEN :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同 RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。此舍入模式类似于 Java 中对 float 和 double 算法使用的舍入策略
输入数字 使用HALF_EVEN舍入模式将输入舍为一位 
5.5
2.5
1.6
1.1
-1.0 -1 
-1.6 -2 
-2.5 -2 
-5.5 -6 

RoundingMode.HALF_UP :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。如果被舍弃部分 >= 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入 
输入数字 使用HALF_UP舍入模式舍入为一位数 
5.5
2.5
1.6
1.0
-1.1 -1 
-1.6 -2 
-2.5 -3 
-5.5 -6 


RoundingMode.UNNECESSARY :用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。如果对生成精确结果的操作指定此舍入模式,则抛出 ArithmeticException
输入数字 使用UNNECESSARY模式 
5.5 抛出 ArithmeticException 
2.5 抛出 ArithmeticException 
1.6 抛出 ArithmeticException 
1.0
-1.0 -1.0 
-1.1 抛出 ArithmeticException 
-1.6 抛出 ArithmeticException 
-2.5 抛出 ArithmeticException 
-5.5 抛出 ArithmeticException


RoundingMode.UP :远离零方向舍入的舍入模式。始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值
输入数字 使用UP舍入模式将输入数字舍入为一位数 
5.5
1.6
1.1
1.0
-1.1 -2 
-1.6 -2 
-2.5 -3 
-5.4 -6



import  java.math.BigDecimal; 
import  java.text.DecimalFormat; 
/** 
 *使用舍入模式的格式化操作 
 **/ 
public class   DoubleFormat { 
    public static void  main(String  args[]){ 
        DoubleFormat format =  new  DoubleFormat(); 
        System.out .println(format.doubleOutPut(12.345, 2)); 
        System.out .println(format.roundNumber(12.335, 2)); 
    } 
    public   String  doubleOutPut(double  v,Integer num){ 
        if ( v == Double.valueOf(v).intValue()){ 
            return  Double.valueOf(v).intValue() +  "" ; 
        }else { 
            BigDecimal b =  new  BigDecimal(Double.toString(v)); 
            return  b.setScale(num,BigDecimal.ROUND_HALF_UP ).toString(); 
        } 
    } 
    public   String  roundNumber(double  v,int  num){ 
        String  fmtString =  "0000000000000000" ;  //16bit 
        fmtString = num>0 ?  "0."   + fmtString.substring(0,num):"0" ; 
        DecimalFormat dFormat =  new  DecimalFormat(fmtString); 
        return  dFormat.format(v); 
    } 
} 
 
 这段代码的输出为:
12.35 
12.34
 



源自:http://tidercreverse.group.iteye.com/group/topic/25085
分享到:
评论

相关推荐

    java中double转化为BigDecimal精度缺失的实例

    下面小编就为大家带来一篇java中double转化为BigDecimal精度缺失的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java中double类型下出现精度计算错误情况下出力方法

     要保证精度就要使用BigDecimal类,而且不能直接从double直接转BigDecimal,要将double转string再转BigDecimal。也就是不能使用BigDecimal(double val) 方法,你会发现没有效果。要使用BigDecimal(String val) 方法...

    Java BigDecimal和double示例及相关问题解析

    主要介绍了Java BigDecimal和double示例及相关问题解析,简单介绍了BigDecimal类的相关内容,分享了两则相关实例,对问题进行了分析,具有一定参考价值,需要的朋友可以了解下。

    BigDecimal 加减乘除运算

    双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是...

    Java 加减乘除工具类(解决精度损失问题)

    BigDecimal b1 = new BigDecimal(Double.toString(value1.doubleValue())); BigDecimal b2 = new BigDecimal(Double.toString(value2.doubleValue())); return b1.add(b2).doubleValue(); } /** * 提供精确的...

    关于java的数值精度

    java程序中数值的精度问题,float、double容易产生精度数值问题,不适合精度计算,而bigdecimal正好解决这一问题

    BigDecimal-CPP-master.zip

    关于浮点数在计算机中的存储方式与精度丢失问题(float,double):https://blog.csdn.net/alzzw/article/details/108132830 可以用此类解决

    精确计算工具类

    BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2).doubleValue(); } /** * 提供精确的减法运算。 * @param v1 被减数 * @...

    Java中BigDecimal的加减乘除、比较大小与使用注意事项

    对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数的操作,下面这篇文章给大家介绍了Java中BigDecimal的加减...

    Java-关于基本数据类型中浮点数计算产生的精度问题

    在基本数据类型中,float和double都表示浮点型数据,而计算机计算采取的是对二进制的计算,所以会存在一定程度上的精度丢失问题。 BigDecimal类是一个大小数操作类,可以用来对超过16位有效位的数据进行精确的运算,...

    Java的数字精确计算问题-BigDecimal

    java的数字运算,偶尔会出现精度的问题,以下阐述的 java的BigDecimal类的使用.  例如:  System.out.println(0.9+0.3); 结果1.2  System.out.println(1.9+0.3); 结果2.1999999999999997  System.out....

    java中BigDecimal进行加减乘除的基本用法

    大家应该对于不需要任何准确计算精度的数字可以直接使用float或double运算,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数的操作。下面这篇文章就给大家介绍介绍关于...

    BigDecimalUtils

    双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是...

    仿WINDOWS简版计算器

    Java SE学习完成后,自己练手项目二,计算器 ... * @return BigDecimal 包装为高精度计算 */ private static BigDecimal getBigDecimal(double number) { return new BigDecimal(number); }

    处理较大数字的PHP库.zip

    一般的float型和Double型数据只可以用来做科学计算或者 是工程计算,由于在商业计算中,要求的数字精度比较高,所以要用到java.math.BigDecimal类,它支持任何精度的定点数,可以用它来精确 计算货币值。

    scalades:Scala中的事件描述

    时间应该是Double还是BigDecimal? 与> =等进行比较时,浮点数很奇怪。但是BigDecimal可能太慢了。 在长时间的仿真中,时间增量对于精度而言可能太小。 有趣的测试性能并进行比较。 使用不透明类型Time而不是简单...

    使用JavaFX实现的中缀转后缀 计算器(可以负数小数点括号)期末作业满分答案,大量注释(行行注释保证看懂)

    利用BigDecimal 大数据类 来保证精度 例如Double 2-1.1=0.89999,在大数据类就无异常 例如 9+(-9)=0 9--6=15 9*(-9--3)= -54 3 + (-2) -1 = 0 -9*(9--2)*-3 = 297 实现了键位绑定 本计算器回退功能是直接...

    JavaDemical:Java 数字API

    常用构造方法:可以将String类型的数字,int,double,long作为构造方法的参数传入进行构造一个BigDecimal对象。 常用方法: 加减乘除 add(BigDecimal) BigDecimal对象中的值相加,然后返回这个对象。 subtract

    javadbf:用于读写Xbase(dBaseDBF)文件的Java库

    Java数据库JavaDBF是一个用于读取和写入XBase文件的Java库。... 但是有一些小的更改可能会破坏您的代码: 现在,数字和双精度类型(N和F)以BigDecimal而不是Double的形式返回。 DBFException现在是RuntimeExce

    mandelbrot:简单的Mandelbrot查看器

    可以交互式缩放到10 -100甚至更大,如果需要更高的精度,所有计算将自动从double切换到BigDecimal。 渲染是渐进式的且经过优化的,因此尽管缩放级别为100的图像的完整渲染可能会超过1个小时,但应用程序仍会保持...

Global site tag (gtag.js) - Google Analytics