`

Java_Double&BigDecimal

    博客分类:
  • Java
 
阅读更多

via: http://www.cnblogs.com/mingforyou/p/3344489.html

 

 

import java.math.BigDecimal;  

import java.math.MathContext;  

  

public class BigDecimalTest {  

  

    /** 

     * @param args 

     * @reference  archie2010 

     * @function 实现将double类型的值转换为BigDecimal类型的值的不同途径以及各途径间的区别 

     * 一:有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1), 

     * 但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。 

     * 这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。 

     * 这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。  

     * 二:另一方面,String 构造方法是完全可预知的:写入 new BigDecimal("0.1") 将创建一个 BigDecimal, 

     * 它正好 等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。  

     * 三:使用public static BigDecimal valueOf(double val) 

     * 使用 Double.toString(double) 方法提供的 double 规范的字符串表示形式将 double 转换为 BigDecimal。  

     * 这通常是将 double(或 float)转化为 BigDecimal 的首选方法, 

     * 因为返回的值等于从构造 BigDecimal(使用 Double.toString(double) 得到的结果)得到的值。  

     */  

    public static void main(String[] args) {  

        // TODO Auto-generated method stub  

        double d1,d2;  

        d1 = 0.10334;  

        d2 = 1234.0;  

        System.out.println("直接输出double类型的值:");  

        printDouble(d1, d2);  

        System.out.println("将double类型直接转换为BigDecimal类型,再输出:");  

        printDoubleToBigDecimal(d1, d2);  

        System.out.println("将double类型转换为String类型,再转换为BigDecimal类型,再输出:");  

        printDoubleToStrToBigDecimal(d1, d2);  

        System.out.println("使用静态方法valueOf将double转换为BigDecimal类型并输出:");  

        printDoubleToBigDecimalWithValueof(d1,d2);  

        System.out.println("直接将double类型值转换为确定精度为3的BigDecimal类型值:");  

        printDoubleToBigDecimalWithPrecision(d1, d2, 3);  

        System.out.println("将double类型值转换为String类型再转换为确定精度(3)的BigDecimal类型值:");  

        printDoubleToBigDecimalWithPrecisionAsStr(d1,d2,3);  

    }  

      

    /** 

     * @param v1:double类型; 

     * @param v2:double类型; 

     * @return 

     * */  

    public static void printDouble(double v1, double v2){  

        System.out.println("d1="+v1);  

        System.out.println("d2="+v2);  

    }  

      

    /** 

     * @param v1:double类型; 

     * @param v2:double类型; 

     * @return 

     * @Constructor public BigDecimal(double val) 

     * 将 double 转换为 BigDecimal,后者是 double 的二进制浮点值准确的十进制表示形式。 

     * 返回的 BigDecimal 的标度是使 (10scale × val) 为整数的最小值。  

     * */  

    public static void printDoubleToBigDecimal(double v1, double v2){  

        BigDecimal d1TobigDe = new BigDecimal(v1);  

        BigDecimal d2TobigDe = new BigDecimal(v2);  

        System.out.println("d1TobigDe="+d1TobigDe);  

        System.out.println("d2TobigDe="+d2TobigDe);  

    }  

      

    /** 

     * @param v1:double类型; 

     * @param v2:double类型; 

     * @return 

     * @Constructor public BigDecimal(String val) 

     * 将 BigDecimal 的字符串表示形式转换为 BigDecimal。 

     * 字符串表示形式由可选符号 '+' ('\u002B') 或 '-' ('\u002D') 组成, 

     * 后跟零或多个十进制数字(“整数”)的序列,可以选择后跟一个小数,也可以选择后跟一个指数。 

     * */  

    public static void printDoubleToStrToBigDecimal(double v1, double v2){  

        BigDecimal d1ToStrToBigDe = new BigDecimal(String.valueOf(v1));  

        BigDecimal d2ToStrToBigDe = new BigDecimal(String.valueOf(v2));  

        System.out.println("d1ToStrToBigDe="+d1ToStrToBigDe);  

        System.out.println("d2ToStrToBigDe="+d2ToStrToBigDe);  

    }  

      

    /** 

     * @param v1:double类型; 

     * @param v2:double类型; 

     * @return 

     * @Constructor public static BigDecimal valueOf(double val) 

     * */  

    public static void printDoubleToBigDecimalWithValueof(double v1, double v2){  

        System.out.println("BigDecimal.valueOf(d1)="+BigDecimal.valueOf(v1));  

        System.out.println("BigDecimal.valueOf(d2)="+BigDecimal.valueOf(v2));  

    }  

      

    /** 

     * @param v1:double类型; 

     * @param v2:double类型; 

     * @return 

     * @Constructor public BigDecimal(double val,MathContext mc)  

     * */  

    public static void printDoubleToBigDecimalWithPrecision(double v1, double v2, int setPrecision){  

        BigDecimal d1ToBigDeWithPre = new BigDecimal(v1, new MathContext(setPrecision));  

        BigDecimal d2ToBigDeWithPre = new BigDecimal(v2, new MathContext(setPrecision));  

        System.out.println("d1ToBigDeWithPre="+d1ToBigDeWithPre);  

        System.out.println("d2ToBigDeWithPre="+d2ToBigDeWithPre);  

    }  

      

    /** 

     * @param v1:double类型; 

     * @param v2:double类型; 

     * @return 

     * @Constructor public BigDecimal(String val,MathContext mc) 

     * 将 BigDecimal 的字符串表示形式转换为 BigDecimal, 

     * 接受与 BigDecimal(String) 构造方法相同的字符串(按照上下文设置进行舍入)。  

     * */  

    public static void printDoubleToBigDecimalWithPrecisionAsStr(double v1, double v2, int setPrecision){  

        BigDecimal d1ToStrToBigDeWithPre = new BigDecimal(String.valueOf(v1), new MathContext(setPrecision));  

        BigDecimal d2ToStrToBigDeWithPre = new BigDecimal(String.valueOf(v2), new MathContext(setPrecision));  

        System.out.println("d1ToStrToBigDeWithPre="+d1ToStrToBigDeWithPre);  

        System.out.println("d2ToStrToBigDeWithPre="+d2ToStrToBigDeWithPre);  

    }  

}

 

运行结果:

直接输出double类型的值:

d1=0.10334

d2=1234.0

将double类型直接转换为BigDecimal类型,再输出:

d1TobigDe=0.10334000000000000130118138486068346537649631500244140625

d2TobigDe=1234

将double类型转换为String类型,再转换为BigDecimal类型,再输出:

d1ToStrToBigDe=0.10334

d2ToStrToBigDe=1234.0

使用静态方法valueOf将double转换为BigDecimal类型并输出:

BigDecimal.valueOf(d1)=0.10334

BigDecimal.valueOf(d2)=1234.0

直接将double类型值转换为确定精度为3的BigDecimal类型值:

d1ToBigDeWithPre=0.103

d2ToBigDeWithPre=1.23E+3

将double类型值转换为String类型再转换为确定精度(3)的BigDecimal类型值:

d1ToStrToBigDeWithPre=0.103

d2ToStrToBigDeWithPre=1.23E+3

 

 

 

BigDecimal是Java中用来表示任意精确浮点数运算的类,在BigDecimal中,使用unscaledValue × 10-scale来表示一个浮点数。其中,unscaledValue是一个BigInteger,scale是一个int。从这个表示方法来看,BigDecimal只能标识有限小数,不过可以表示的数据范围远远大于double,在实际应用中基本足够了。

下面提一下两个精度问题:

 

问题一:BigDecimal的精度问题(StackOverflow上有个家伙问了相关的问题)

System.out.println(new BigDecimal(0.1).toString()); // 0.1000000000000000055511151231257827021181583404541015625

System.out.println(new BigDecimal("0.1").toString()); // 0.1

System.out.println(new BigDecimal(

Double.toString(0.1000000000000000055511151231257827021181583404541015625)).toString());// 0.1

System.out.println(new BigDecimal(Double.toString(0.1)).toString()); // 0.1

 

分析一下上面代码的问题(注释的内容表示此语句的输出)

 

第一行:事实上,由于二进制无法精确地表示十进制小数0.1,但是编译器读到字符串"0.1"之后,必须把它转成8个字节的double值,因此,编译器只能用一个最接近的值来代替0.1了,即0.1000000000000000055511151231257827021181583404541015625。因此,在运行时,传给BigDecimal构造函数的真正的数值是0.1000000000000000055511151231257827021181583404541015625。

第二行:BigDecimal能够正确地把字符串转化成真正精确的浮点数。

第三行:问题在于Double.toString会使用一定的精度来四舍五入double,然后再输出。会。Double.toString(0.1000000000000000055511151231257827021181583404541015625)输出的事实上是"0.1",因此生成的BigDecimal表示的数也是0.1。

第四行:基于前面的分析,事实上这一行代码等价于第三行

 

结论:

1.如果你希望BigDecimal能够精确地表示你希望的数值,那么一定要使用字符串来表示小数,并传递给BigDecimal的构造函数。

2.如果你使用Double.toString来把double转化字符串,然后调用BigDecimal(String),这个也是不靠谱的,它不一定按你的想法工作。

3.如果你不是很在乎是否完全精确地表示,并且使用了BigDecimal(double),那么要注意double本身的特例,double的规范本身定义了几个特殊的double值(Infinite,-Infinite,NaN),不要把这些值传给BigDecimal,否则会抛出异常。

 

问题二:把double强制转化成int,难道不是扔掉小数部分吗?

int x=(int)1023.99999999999999; // x=1024为什么?

原因还是在于二进制无法精确地表示某些十进制小数,因此1023.99999999999999在编译之后的double值变成了1024。

 

所以,把double强制转化成int确实是扔掉小数部分,但是你写在代码中的值,并不一定是编译器生成的真正的double值。

验证代码:

double d = 1023.99999999999999;

int x = (int) d;

System.out.println(new BigDecimal(d).toString()); // 1024

System.out.println(Long.toHexString(Double.doubleToRawLongBits(d))); // 4090000000000000

System.out.println(x); // 1024

前面提过BigDecimal可以精确地把double表示出来还记得吧。

 

我们也可以直接打印出d的二进制形式,根据IEEE 754的规定,我们可以算出0x4090000000000000=(1024)。

分享到:
评论

相关推荐

    java_double_精度

    Java 中的双精度浮点数(double)类型在进行运算时经常出现精度丢失的问题,这是由于双精度浮点数在计算机内部的存储方式所致。双精度浮点数使用 64 位二进制数来存储小数,然而这种存储方式会导致某些小数无法精确...

    BigDecimal向Double转换

    本文将详细介绍如何在Java中实现BigDecimal到Double的转换,并探讨转换过程中需要注意的关键点。 ## 一、BigDecimal简介 ### 1.1 BigDecimal的概念 BigDecimal是java.math包下的一个类,它提供了对不可变的、任意...

    java-BigInteger-BigDecimal类源码

    在Java编程语言中,`BigInteger`和`BigDecimal`是两个重要的类,它们分别用于处理大整数和高精度浮点数。这两个类位于`java.math`包下,为开发者提供了超越基本数据类型(如int、long和double)的计算能力。在深入...

    java中BigDecimal的操作方法

    在Java编程语言中,BigDecimal是用于处理高精度和可配置精度的十进制数的类。在进行商业计算时,由于浮点数(double和float)存在精度问题,不能保证准确的结果,因此通常推荐使用BigDecimal来确保计算的精确性。本文...

    Java Double相加出现的怪事

    在《Effective Java》这本书中也提到这个原则,float 和 double 只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal。BigDecimal 一共有 4 个够造方法,我们可以使用 BigDecimal(double ...

    Java Double 精度问题总结

    ### Java Double 精度问题总结 在Java编程语言中,`double` 类型是一种用于表示64位浮点数的原始数据类型。虽然 `double` 提供了相对较高的精度,但在涉及精确数学运算(特别是涉及到小数值)时,由于其内部采用二...

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

    Java BigDecimal和double示例及相关问题解析 在 Java 中,浮点数的表示形式有多种,包括 float 和 double 等,但是这些类型在进行计算时会出现精度问题,而 BigDecimal 则可以解决这种问题。本文将主要介绍 Java 中...

    关于java中BigDecimal的简介(csdn)————程序.pdf

    Java中的`BigDecimal`类是用于表示和操作高精度浮点数的重要工具,尤其适用于需要进行精确计算的场景,如财务和货币计算。由于基本数据类型`double`和`float`在进行大数值或高精度计算时可能会导致精度丢失,因此`...

    Java对BigDecimal常用方法的归类(加减乘除).doc

    Java 中 BigDecimal 的常用方法归类(加减乘除) Java 中的 BigDecimal 类提供了对浮点数的精确运算,包括加减乘除和四舍五入等操作。在 Java 中,简单类型不能够精确地对浮点数进行运算,因此需要使用 BigDecimal ...

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

    在Java编程中,当涉及到需要精确数值计算的场景时,我们通常会使用`BigDecimal`类。这是因为`float`和`double`类型虽然适用于科学计算和工程计算,但它们基于二进制浮点运算,不能保证完全精确的结果。而`BigDecimal...

    Java BigDecimal使用及基本运算(推荐)

    由于 double 和 float 类型在处理大数或需要绝对精确计算的场景下存在精度损失,因此 BigDecimal 成为了商业计算和金融计算的标准工具。 在使用 BigDecimal 时,我们需要通过构造函数来创建对象,通常我们会传入一...

    BigDecimal 加减乘除运算

    float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的...

    BigDecimal工具类.docx

    BigDecimal工具类是Java中用于高精确处理常用数学运算的工具类。该工具类提供了多种精确的数学运算方法,包括加法、减法、乘法和除法等。 在BigDecimal工具类中,我们可以看到多个重载的方法,例如add方法和sub方法...

    Java中BigDecimal类的使用详解

    Java中BigDecimal类的使用详解 Java中BigDecimal类是Java.math包中提供的一个API类,用于对超过16位有效位的数进行精确的运算。由于浮点数的精度问题,Java中浮点数的计算会失去一定的精确度。因此,使用BigDecimal...

    Java中BigDecimal的基本运算(详解)

    Java中BigDecimal的基本运算详解 Java中的BigDecimal是一种高精度的数据类型,它可以用来表示非常大的整数和小数,提供了丰富的数学运算功能。下面我们将对Java中BigDecimal的基本运算进行详细的介绍。 构造方法 ...

    bigdecimal

    ### Java中的BigDecimal类详解 在Java编程语言中,当我们处理涉及货币、财务或者任何需要高精度计算的场景时,`BigDecimal` 类是非常重要的工具之一。本文将深入探讨 `BigDecimal` 类的基本概念、特点以及如何使用...

    Java BigDecimal详解_动力节点Java学院整理

    借用《Effactive Java》这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供...

    BigDecimal类

    BigDecimal 类是 Java 中的一种数值类型,主要用于处理超过 16 位有效数字的数值运算。该类提供了多种构造器和方法,用于创建和操作 BigDecimal 对象。 构造器 BigDecimal 类提供了四种构造器,用于创建不同的 ...

    Java用BigDecimal解决double类型相减时可能存在的误差

    在Java编程语言中,`double`类型用于表示浮点数,但存在精度问题,尤其是在进行数学运算时。这是因为`double`是基于二进制浮点数标准(IEEE 754)来存储和计算的,这可能导致计算结果与预期的十进制值存在微小的差异...

    java实现大数加法(BigDecimal)的实例代码

    与Java中的`int`, `long`, `float`, `double`等基本类型不同,`BigDecimal`不依赖于机器的浮点数表示,因此可以进行精确的算术运算,避免了浮点数运算常见的精度损失问题。 在给定的实例代码中,我们首先创建两个`...

Global site tag (gtag.js) - Google Analytics