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]);
    }
}

在这里插入图片描述

2.1.3常用方法

NO.方法类型描述
1public BigInteger(String val)构造将一个字符串变为 BigInteger类型的数据
2public BigInteger add(BigInteger val)普通加法
3public BigInteger subtract(BigInteger val)普通减法
4public BigInteger multiply(BigInteger val)普通乘法
5public BigInteger divide(BigInteger val)普通除法
6public BigInteger max(BigInteger val)普通最大值
7public BigInteger min(BigInteger val)普通最小值
8public 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]);
    }
}

在这里插入图片描述

2.2.3常用方法

NO.方法类型描述
1public BigDecimal(String val)构造将一个字符串变为 BigDecimal类型的数据
2public BigDecimal add(BigDecimal augend)普通加法
3public BigDecimal subtract(BigDecimal subtrahend)普通减法
4public BigDecimal multiply(BigDecimal multiplicand)普通乘法
5public BigDecimal divide(BigDecimal divisor)普通除法
6public BigDecimal max(BigDecimal val)普通最大值
7public BigDecimal min(BigDecimal val)普通最小值
8public 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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许进进

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值