在实际开发中,难免会遇到数据值的计算,关于小数的两种浮点型(float,double),也就是单精度与双精度。
那么就需要一个类帮我们解决一些问题,下面介绍两种浮点型的区别和BigDecimal类的使用
两种类型的区别:
1.在内存中占有的字节数:单精度是4字节,而双精度是8字节
2. 有效数字位数:单精度有效位是8位,双精度是16位
3. 数值取值范围:单精度表示范围 -3.40E+38~3.40E+38,双精度表示范围 -1.79E+308~-1.79E+308
4. 在程序中处理速度不同:一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快(网上是这样说,还没有感受过)
5. 两者在使用定义时:如果定义是不声明,默认的小数类型就是double,如果要使用float就必须进行强制转换
6. 例如:float a=1.5; 会编译报错,正确的写法 float a = (float)1.5;或者float a = 1.5f;(f或F都可以不区分大小写)
BigDecimal类:
先介绍下 BigDecimal 类的常用方法
BigDecimal 类路径:java.math.BigDecimal,BigDecimal 的父类是一个抽象类Number 类路径 java.lang.Number
比如很多熟悉的基本类型包装类:Byte、Long、Integer都来继承自此类
作用:用于高精度的浮点运算
- 创建 BigDecimal类(构造方法)
new BigDecimal(int) 创建一个具有参数所指定整数值的对象。
new BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
new BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
new BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。
注:在创建BigDecimal对象时,如果直接传入的是小数类型的值,有可能会造成精度损失,推荐传入String类型
- 常用方法
1.BigDecimal add(BigDecimal value); 加法,求两个BigDecimal类型数据的和。
2.BigDecimal subtract(BigDecimal value); 减法,求两个BigDecimal类型数据的差。
3.BigDecimal multiply(BigDecimal value); 乘法,求两个BigDecimal类型数据的积。
4.BigDecimal divide(BigDecimal divisor); 除法,求两个BigDecimal类型数据的商。
5.BigDecimal remainder(BigDecimal divisor); 求余数,求BigDecimal类型数据除以divisor的余数。
6.BigDecimal max(BigDecimal value); 最大数,求两个BigDecimal类型数据的最大值。
7.BigDecimal min(BigDecimal value); 最小数,求两个BigDecimal类型数据的最小值。
8.BigDecimal abs(); 绝对值,求BigDecimal类型数据的绝对值。
9.BigDecimal negate(); 相反数,求BigDecimal类型数据的相反数。
10.BigDecimal setScale(int newScale, int roundingMode); 按指定舍入模式保留小数位数
怎么用?下面给大家举个加法的例子 BigDecimal add(BigDecimal value);:
@Test
public void decimal() {
/*1.第一个BigDecimal的小数值 1.57361*/
BigDecimal bigDecimal = new BigDecimal("1.57361");
/*2.第二个BigDecimal的小数值 1.5*/
BigDecimal bigDecimal2 = new BigDecimal("1.5");
/*使用第一个BigDecimal下的add(BigDecimal value)方法 去加上bigDecimal2的数值
* 这里就相当于 1.5361 + 1.5*/
BigDecimal add = bigDecimal.add(bigDecimal2);
/*结果:3.07361*/
System.out.println(add);
/*如果还要舍弃后面的多余小数,比如说:只保留两位小数点
* 参数一:设置需要保留小数的位数
参数二:舍入模式(8种舍入方式下面有详细介绍)*/
BigDecimal decimal = add.setScale(2, BigDecimal.ROUND_UP);
/*输出舍入后的值:3.08 (舍入模式会间接影响结果)
比如这里结果其实是3.07,使用的舍入方式向前进了一位*/
System.out.println(decimal);
}
- 获取 BigDecimal 对象中不同返回值类型
String toString() 将BigDecimal对象的数值转换成字符串。
double doubleValue() 将BigDecimal对象中的值以双精度数返回。
float floatValue() 将BigDecimal对象中的值以单精度数返回。
long longValue() 将BigDecimal对象中的值以长整数返回。
int intValue() 将BigDecimal对象中的值以整数返回。
BigDecimal类的8中不同的舍入方式:
假设现在有一个浮点型小数:1.375411 看看使用下面不同的舍入方式会有什么样的结果?
1.BigDecimal.ROUND_UP 常量值 = 0 (作用:在保留小数后直接去掉多余的位数)
案例:1.376411 ➡ 1.376
2.BigDecimal.ROUND_DOWN 常量值 = 1 (作用:在保留小数后向前进一位)
案例:1.376411 ➡ 1.377
3.BigDecimal.ROUND_CEILING 常量值 = 2 (作用:如果是正数相当于ROUND_DOWN,负数相当于ROUND_UP)
4.BigDecimal.ROUND_FLOOR 常量值 = 3 (作用:如果是正数相当于ROUND_DOWN,ROUND_HALF_UP)
5.BigDecimal.ROUND_HALF_UP 常量值 = 4 (作用:在舍弃部分左边的数字四舍五入(若舍入部分>=5,就进位))
案例:1.376411 ➡ 1.376 如果 1.376511 变为 1.377
6.BigDecimal.ROUND_HALF_DOWN 常量值 = 5 (作用:在保留小数后的后一位四舍五入(若舍入部分>5,就进位) 和ROUND_HALF_UP非常相似)
案例:1.376411 ➡ 1.376,如果是1.376511 ➡ 1.377
注意 ROUND_HALF_UP与ROUND_HALF_DOWN的作用都相同,区别在前者是舍入部分大于或等于>=5都进位,后者只有舍入部分大于>5才进位
7.BigDecimal.ROUND_HALF_EVEN 常量值 = 6 (作用:如果舍入部分左边的数字为偶数情况下作用与ROUND_HALF_DOWN相同,为奇数与ROUND_HALF_UP相同)
案例:1.376411 ➡ 1.376 舍入部分左边数字为6(偶数),再使用ROUND_HALF_DOWN,舍入部分为411 没有大于>5 那么不进位(相反之)
再比如:1.375511 ➡ 1.376 舍入部分左边数字为5(奇数),再使用ROUND_HALF_UP,舍入部分为511 大于>=5 那么进位(相反之) 1.375 ➡ 1.376
逻辑: 1.先判断舍入部分左边数字为偶数还是奇数
2.再选择使用ROUND_HALF_DOWN(偶数)还是 ROUND_HALF_UP(奇数)
使用的方式是银行家舍入:即四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一(可以去了解下)
8.BigDecimal.ROUND_UNNECESSARY 常量值 = 7 (作用:断言该小数已经具有精确的结果,因此不需要舍入。否则抛出ArithmeticException异常)
例子:1.376 只要小数位不超过规定的位数(我们这里是3位),超过抛出异常
注:该方法是一个重载方法 java.math.RoundingMode枚举类中就包含上面8个常量
案例:
假设现在有一个浮点型小数我们需要按照我们的要求进行保留小数位:
@Test
public void decimal() {
/*1.创建 BigDecimal类
注:在创建BigDecimal对象时,如果直接传入的是小数类型的值,有可能会造成精度损失,推荐传入String类型*/
BigDecimal Decimal = new BigDecimal("1.376411");
/*2.使用BigDecimal.setScale(int newScale, int roundingMode)方法进行小数位的保留
参数一:设置需要保留3位小数
参数二:舍入模式(8种舍入方式上面已经介绍了)
这里就保留3位小数,使用BigDecimal.ROUND_UP方式:在保留小数后直接去掉多余的位数(这里写对应的常量值也行)*/
Decimal = Decimal.setScale(3, BigDecimal.ROUND_UP);
/*3.获取返回类型(可以获得不同的返回值类型:long,int,String,double)*/
double value = Decimal.doubleValue();
/*打印输出*/
System.out.println(value);
/*不同的舍入方式大家可以参照这上面的关于舍入方式详细介绍都试一试*/
}