0
点赞
收藏
分享

微信扫一扫

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类)_java

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类)_java_02

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(); // 向下取整

举报

相关推荐

0 条评论