Java:float/double的精度问题以及大数/小数操作(BigInteger类、BigDecimal类)

一: int、float、double精度问题

float/int占32位(bit)4字节,double占 64位8字节。

float ,1位符号位, 8位指数位,23位尾数位
double,1位符号位,11位指数位,52位尾数位
float尾数位23位,2^23=8.3E6,7位,所以不同的编译器规定不同,有些是7位,有些8位
double尾数52位,2^52=4.5E15,15位,所以double的有效位数是15位

结论:数一下有效数字位数(整数位+小数位),7位以内的用float,15位以内的用double

二:大小数操作

2.1 大数BigInteger类

BigInteger类 与 BigDecimal类 都在 java.math包 中

2.1.1应用场景

在正常情况下一个整数最多只能保存在 long类型中,但如果有这么个数字:123456789012345678901234567890

我们就头疼了,因为 long类型 的整数范围是有限的,无法保存这么大的一个数字,更不用说做大数运算了,那该怎么办呢?为了解决这一个问题,在 Java中 引入了专门用来进行大数操作的一个类 —— BigInteger类。

有了 BigInteger类,我们可以很方便的进行大数的操作。当然了,这些大数的数据都会以字符串的形式写入。

2.1.2代码

import java.math.BigInteger;

public class Test {
    public static void main(String[] args) {
        // 用来保存 两个大数
        BigInteger b1 = new BigInteger("987654321098765432109876543210");
        BigInteger b2 = new BigInteger("123456789012345678901234567890");

        // 两个大数的运算(加减乘除、最大值、最小值)
        System.out.println("b1 + b2 = " + b1.add(b2));        // 加
        System.out.println("b1 - b2 = " + b1.subtract(b2));   // 减
        System.out.println("b1 * b2 = " + b1.multiply(b2));   // 乘
        System.out.println("b1 / b2 = " + b1.divide(b2));     // 除
        System.out.println("max: " + b1.max(b2));        // 最大值
        System.out.println("min: " + b1.min(b2));        // 最小值
        System.out.println();

        // 除法操作,数组的第一个元素是除法的商,第二个元素是除法的余数
        BigInteger[] bArr = b1.divideAndRemainder(b2);
        System.out.println("商:" + bArr[0]);
        System.out.println("余数:" + bArr[1]);
    }
}

Java:float/double的精度问题以及大数/小数操作(BigInteger类、BigDecimal类)_第1张图片

2.1.3常用方法

NO. 方法 类型 描述
1 public BigInteger(String val) 构造 将一个字符串变为 BigInteger类型的数据
2 public BigInteger add(BigInteger val) 普通 加法
3 public BigInteger subtract(BigInteger val) 普通 减法
4 public BigInteger multiply(BigInteger val) 普通 乘法
5 public BigInteger divide(BigInteger val) 普通 除法
6 public BigInteger max(BigInteger val) 普通 最大值
7 public BigInteger min(BigInteger val) 普通 最小值
8 public BigInteger[] divideAndRemainder(BigInteger val) 普通 除法操作,数组的第一个元素表示除法的商,
第二个元素表示除法的余数

2.2小数BigDecimal类

2.2.1应用场景

在日常开发中我们经常会碰到小数运算,而小数直接进行运算的话会出现一些,请看下列代码:

System.out.println(2.00 - 1.10);

如果不看输出结果,我们很有可能会认为输出的是 0.9,可真正输出的却是0.8999999999999999。这是为什么呢?这是因为我们计算机在进行浮点运算时,采用的是二进制运算,这样做非常容易导致精度丢失(如上列代码)。

那遇到这种问题到底该怎么办呢?别着急,为了解决这一个问题,在 Java中 又引入一种了专门用来进行小数操作的一个类 —— BigDecimal类。

自从有了 BigDecimal类,我们不仅可以很方便的进行小数的操作,而且再也不会发生精度丢失的问题了。当然了,这些小数据都也是以字符串的形式写入,因为如果使用浮点形式写入,又会发生精度丢失的问题了。

2.2.2 代码

import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        // 用来保存 两个小数
        BigDecimal b1 = new BigDecimal("1.00");
        BigDecimal b2 = new BigDecimal("0.30");

        // 两个小数的运算(加减乘除、最大值、最小值)
        System.out.println("b1 + b2 = " + b1.add(b2));        // 加
        System.out.println("b1 - b2 = " + b1.subtract(b2));   // 减
        System.out.println("b1 * b2 = " + b1.multiply(b2));   // 乘
        // 除法,开始四舍五入模式,否则可能会报 ArithmeticException
        System.out.println("b1 / b2 = " + b1.divide(b2, BigDecimal.ROUND_HALF_UP));
        System.out.println("max: " + b1.max(b2));        // 最大值
        System.out.println("min: " + b1.min(b2));        // 最小值
        System.out.println();

        // 除法操作,数组的第一个元素是除法的商,第二个元素是除法的余数
        BigDecimal[] bArr = b1.divideAndRemainder(b2);
        System.out.println("商:" + bArr[0]);
        System.out.println("余数:" + bArr[1]);
    }
}

Java:float/double的精度问题以及大数/小数操作(BigInteger类、BigDecimal类)_第2张图片

2.2.3常用方法

NO. 方法 类型 描述
1 public BigDecimal(String val) 构造 将一个字符串变为 BigDecimal类型的数据
2 public BigDecimal add(BigDecimal augend) 普通 加法
3 public BigDecimal subtract(BigDecimal subtrahend) 普通 减法
4 public BigDecimal multiply(BigDecimal multiplicand) 普通 乘法
5 public BigDecimal divide(BigDecimal divisor) 普通 除法
6 public BigDecimal max(BigDecimal val) 普通 最大值
7 public BigDecimal min(BigDecimal val) 普通 最小值
8 public BigDecimal[] divideAndRemainder(BigDecimal divisor) 普通 除法操作,数组的第一个元素表示除法的商,
第二个元素表示除法的余数

三: BigDecimal 转float

BigDecimal tt = new BigDecimal(50) ;
 float kk = tt.floatValue();

四: 注意事项

JAVA中如果用BigDecimal做除法的时候一定要在divide方法中传递第二个参数,定义精确到小数点后几位,否则在不整除的情况下,结果是无限循环小数时,就会抛出异常:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result

解决方法:

foo.divide(bar, 2, BigDecimal.ROUND_HALF_UP);

五: 取整

BigDecimal bd = new BigDecimal("12.1");
long l  = bd.setScale( 0, BigDecimal.ROUND_UP ).longValue(); // 向上取整
long l  = bd.setScale( 0, BigDecimal.ROUND_DOWN ).longValue(); // 向下取整

参考文章:
https://blog.csdn.net/sun8112133/article/details/81291750
https://www.cnblogs.com/vineleven/p/8267005.html
https://www.cnblogs.com/LeoBoy/p/5897754.html

你可能感兴趣的:(java)