首页 > 编程语言 >Java_Double&BigDecimal

Java_Double&BigDecimal

时间:2023-04-14 11:36:01浏览次数:45  
标签:Java BigDecimal Double System double println new out

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,BigDecimal,Double,System,double,println,new,out
From: https://blog.51cto.com/u_16070335/6189760

相关文章

  • Java_获取变量的类型
    如果是对象,那么可以使用getClass().getName()方法获得该对象的类名,然,还有就是利用反射机制获取原数据类型的,这个时候如果需要确定类型, 同样的,反射机制返回值是对象,比如对于类属性的返回,是Field对象,可以 通过里面的getType().getName()获得该属性的类型名称,下面一个例子:Type ......
  • Java_procedure with return value(oracle)
    Java调用Oracle中有返回值的存储过程1) 在编写存储过程时,输入参数用in(如果不写默认为in),输出参数用out --编写过程,要求输入雇员编号,返回雇员姓名。 createorreplaceproceduregetNameByNo(noinnumber,nameoutvarchar2)is begin  selectenameintonamefrom......
  • Java使用TensorFlow
    Java可以使用TensorFlow,TensorFlow为Java提供了一个API,它可以让Java开发者使用TensorFlow构建和训练深度学习模型。以下是如何在Java中使用TensorFlow的基本步骤:首先,需要安装TensorFlow的JavaAPI,可以从TensorFlow官网下载安装包,或者通过Maven或Gradle添加依赖。然后,在Java......
  • MariaDB_About the MariaDB Java Client
    via: https://mariadb.com/kb/en/about-the-mariadb-java-client/ IntroductionTheMariaDBClientLibraryforJavaApplicationsisaType4JDBCdriver.ItwasdevelopedspecificallyasalightweightJDBCconnectorforusewithMySQLandMariaDBdatabaseser......
  • Java中File类中常用的一些方法
    File.delete()删除文件或文件夹目录。File.createNewFile()创建一个新的空文件。File.mkdir()创建一个新的空文件夹。File.list()获取指定目录下的文件和文件夹名称。File.listFiles()获取指定目录下的文件和文件夹对象。File.exists......
  • 半小时实现Java网络爬虫框架
    最近在做一个搜索相关的项目,需要爬取网络上的一些链接存储到索引库中,虽然有很多开源的强大的爬虫框架,但本着学习的态度,自己写了一个简单的网络爬虫,以便了解其中的原理。今天,就为小伙伴们分享下这个简单的爬虫程序!!首先介绍每个类的功能:DownloadPage.java的功能是下载此超链接的页......
  • Java_判断操作系统类型
    Java判断操作系统类型(适用于各种操作系统)/***平台*@authorisea533*/publicenumEPlatform{Any("any"),Linux("Linux"),Mac_OS("MacOS"),Mac_OS_X("MacOSX"),Windows("Windows"),OS2("OS......
  • Java基础---数据类型
    数据类型Java的两大数据类型:内置数据类型、引用数据类型内置数据类型Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。byte、short、int、long、float、double、char、boolean基本类型范围byte:(8位)-128~127short:(26......
  • JavaScript 之 confirm,alert,prompt
    //confirmfunctiondisp_confirm(){varr=confirm("Pressabutton!")if(r==true){alert("YoupressedOK!")}else{alert("YoupressedCancel!")}}//alert<script>window.alert("确......
  • Java_打包
     发布打war包dos命令:jarcvfname.war. war包是带jsp页面,jar包不带jsp页面的. 在JDK的bin目录下提供了打包程序jar.exe。如果要展开helloapp.war文件,命令为:jarxvfhelloapp.war  假定有一个Web应用:C:\myHomemyHome/WEB-INF/……myHome/files/……myHome/image/……myHome/......