源码分析double和BigDecimal区别

一:double分析

double 类型的底层实现是使用 IEEE 754 标准来表示浮点数。在 Java 中,double 类型的变量占用 8 个字节,其中 1 个字节用于表示符号位,11 个字节用于表示指数,剩余的 52 个字节用于表示尾数。由于尾数只有 52 个字节,因此 double 类型能够精确表示的数字是有限的。在 Java 中,double 类型的值可以用以下公式来计算:

value = (-1)^s * m * 2^e

其中,s 表示符号位,m 表示尾数,e 表示指数。在 double 类型中,符号位占用 1 个字节,尾数占用 52 个字节,指数占用 11 个字节。

在 double 类型中,尾数使用二进制表示,指数使用移位表示。具体来说,指数的值先减去 1023,然后再左移 52 位。这样可以将指数的二进制表示与尾数的二进制表示拼接起来,得到一个 64 位的二进制数,表示一个 double 类型的值。

double 类型的运算是通过对二进制数进行位运算来实现的。例如,两个 double 类型的值相加时,先将它们的二进制表示对齐,然后逐位相加,并将进位的部分保存下来。这样可以保证精度,并避免浮点数精度问题导致的计算错误。

二:BigDecimal分析

BigDecimal 类的底层实现是使用一个整数数组来表示一个高精度的十进制数字。在 Java 中,BigDecimal 类的实现方式可以分为两种:基于 int 数组的实现方式和基于 long 数组的实现方式。这两种实现方式的区别在于使用的数组类型不同,但它们的原理都是一样的。

在 BigDecimal 类中,每个数字都是用一个 int 或 long 类型的变量来表示的。例如,对于一个十进制数 123456789,可以使用一个 int 数组来表示它:

int[] digits = {9, 8, 7, 6, 5, 4, 3, 2, 1};

在 BigDecimal 类中,还定义了一些常量,例如 ZERO、ONE、TEN 等。这些常量都是 BigDecimal 类型的对象,用于表示常见的数字。

BigDecimal 类提供了各种精确计算方法,包括加、减、乘、除等操作。在进行这些操作时,BigDecimal 类会根据实际情况选择合适的算法来保证精度。例如,在进行加法操作时,BigDecimal 类会将两个 BigDecimal 对象的小数部分对齐,然后逐位相加,并将进位的部分保存下来。这样可以保证精度,并避免浮点数精度问题导致的计算错误。

常用方法

BigDecimal 是 Java 中用于高精度计算的数据类型,它提供了很多常用的方法来进行数值计算和格式化。下面是一些常用的 BigDecimal 方法和示例代码:

BigDecimal bd1 = new BigDecimal("10.5");
BigDecimal bd2 = new BigDecimal("20.3");
BigDecimal result = bd1.add(bd2);
System.out.println(result); // 输出 30.8
BigDecimal bd1 = new BigDecimal("10.5");
BigDecimal bd2 = new BigDecimal("20.3");
BigDecimal result = bd2.subtract(bd1);
System.out.println(result); // 输出 9.8
BigDecimal bd1 = new BigDecimal("10.5");
BigDecimal bd2 = new BigDecimal("20.3");
BigDecimal result = bd1.multiply(bd2);
System.out.println(result); // 输出 213.15
BigDecimal bd1 = new BigDecimal("10.5");
BigDecimal bd2 = new BigDecimal("20.3");
BigDecimal result = bd2.pide(bd1, 2, RoundingMode.HALF_UP);
System.out.println(result); // 输出 1.93
BigDecimal bd1 = new BigDecimal("10.555");
BigDecimal result = bd1.setScale(2, RoundingMode.HALF_UP);
System.out.println(result); // 输出 10.56
BigDecimal bd1 = new BigDecimal("10.5");
int result = bd1.intValue();
System.out.println(result); // 输出 10
BigDecimal bd1 = new BigDecimal("10.5");
double result = bd1.doubleValue();
System.out.println(result); // 输出 10.5
BigDecimal bd1 = new BigDecimal("10.5");
String result = bd1.toString();
System.out.println(result); // 输出 10.5

需要注意的是,在使用 BigDecimal 进行计算时,应该使用 BigDecimal 的方法进行计算,而不是使用 double 进行计算后再转换成 BigDecimal。因为这样可能会导致精度问题。例如:

double a = 0.1;
double b = 0.2;
BigDecimal x = new BigDecimal(a); // 将 double 转换成 BigDecimal
BigDecimal y = new BigDecimal(b); // 将 double 转换成 BigDecimal
BigDecimal z = x.add(y); // 使用 BigDecimal 进行计算

在上面的代码中,先将 double 类型的变量转换成 BigDecimal,然后使用 BigDecimal 进行相加操作。但是,由于 double 类型的变量已经存在精度误差,所以再将其转换成 BigDecimal 时,这种精度误差也会被保留下来。因此,得到的结果仍然是不精确的。

三:BigDecimal精度高原因

BigDecimal 的精度比 double 高的原因在于它使用了十进制表示法,而 double 使用的是二进制表示法。在十进制表示法中,每一位都代表一个十进制的数,因此可以精确地表示小数。而在二进制表示法中,有些小数无法精确表示,例如 0.1 在二进制中是无限循环小数 0.0001100110011...,因此在计算机中以二进制形式存储时会存在精度损失。

BigDecimal 的另一个优势是可以设置任意精度,而 double 的精度是有限的。这意味着 BigDecimal 可以处理任意位数的小数,而 double 只能处理 15 到 17 位小数。

四:两者使用场景

double 和 BigDecimal 都是 Java 中表示浮点数的数据类型,但它们有不同的使用场景。

double :高速计算

例如科学计算、图形处理等。double 使用 64 位来存储一个浮点数,可以表示的范围为正负 1.7976931348623157 x 10^308,精度为 15 到 16 位有效数字。在计算机科学中,double 是一种常用的数据类型,因为它的计算速度比较快,但精度不够高。

BigDecimal :高精度计算

例如财务计算、货币计算等。BigDecimal 使用任意精度的整数来表示一个浮点数,因此可以表示任意位数的小数。BigDecimal 的精度可以通过设置参数来指定,因此可以避免 double 的精度误差问题。在 Java 中,BigDecimal 的计算速度通常比 double 慢,但可以保证精度和准确性。

需要注意的是,在使用 BigDecimal 进行计算时,必须使用 String 类型的参数来初始化 BigDecimal 对象,否则可能会出现精度误差。另外,由于 BigDecimal 是一种高精度计算的数据类型,因此在处理大量数据时,可能会消耗大量的内存和计算资源。

五:总结

使用 BigDecimal 进行运算的速度比使用 double 慢得多,因为 BigDecimal 需要进行更多的计算。因此,在需要高精度计算的情况下,应该使用 BigDecimal,而在需要高效计算的情况下,应该使用 double。

展开阅读全文

页面更新:2024-02-08

标签:尾数   可能会   小数   数组   误差   位数   字节   精度   源码   区别   指数   类型

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top