根本数据类型
浮点数存在误差
浮点数有一个须要特地留神的点就是浮点数是有误差的,比方以下这段代码你感觉输入的什么后果:
public class Demo { public static void main(String[] args) { System.out.println(0.1+0.2 == 0.3);//输入false }}
这段代码输入值是false,之所以是这个后果那是因为浮点数是存在误差的,也就yi是说0.1在计算机中存储时不是准确的0.1,而有可能是0.1000000001,或者其余数,而0.2或0.3也是如此,所以0.1+0.2和0.3在计算机中是不相等的。
因为浮点数存在这个个性,所以咱们在编程两头要尽量避免用浮点数进行比拟。
如果非要用浮点数进行比拟的话,那能够应用上面这个办法:
public class Demo { public static void main(String[] args) { float n = (float)1e-6;//示意10的-6次方 System.out.println(0.1+0.2 - 0.3 < n);//输入true }}
以上代码的输入值是true,该办法的原理是如果两个数相差足够小,小到能够疏忽不记的话,这里的界线设置是10的-6次方,那证实比拟的这两个数能够认为是相等的,此办法只能在所示意的浮点数的小数点后的位数不是很多的时候应用。
接下来咱们再来看一种极其的状况,代码如下:
public class Demo { public static void main(String[] args) { System.out.println(0.30000000000000001 == 0.3);//输入true }}
以上的代码输入true,但其实咱们肉眼能够很直观的看出,这两个数尽管很靠近,但他们相对不相等,像这种极其的数咱们是无奈用下面的办法进行比拟的,所以还是记住这句话:尽量避免对浮点数进行比拟。
BigDecimal类
咱们既然晓得了浮点数是存在误差的,所以在数据自身须要精确精度存储时,咱们是肯定不会应用float和double的,比方金钱数额的存储。这时咱们通常应用BigDecimal
类进行存储,它是一个能够存储精确浮点数的类。
BigDecimal
类的定义:
BigDecimal bd = new BigDecimal("123.456");
BigDecimal
应用scale()
示意小数位数,例如:
BigDecimal d1 = new BigDecimal("987.65"); BigDecimal d2 = new BigDecimal("987.6500"); BigDecimal d3 = new BigDecimal("98765400"); System.out.println(d1.scale()); // 2,示意两位小数 System.out.println(d2.scale()); // 4 System.out.println(d3.scale()); // 0
BigDecimal
中的stripTrailingZeros()
办法,能够将BigDecimal
格式化为去掉数值开端0的相等的数:
BigDecimal d1 = new BigDecimal("123.4500"); BigDecimal d2 = d1.stripTrailingZeros(); System.out.println(d1+" "+d1.scale()); // 123.4500 4 System.out.println(d2+" "+d2.scale()); // 123.45 2,因为去掉了00 BigDecimal d3 = new BigDecimal("1234500"); BigDecimal d4 = d3.stripTrailingZeros(); System.out.println(d3+" "+d3.scale()); // 1234500 0 System.out.println(d4+" "+d4.scale()); // 1.2345E+6 -2
BigDecimal
的scale()
返回正数,例如,-2
,示意这个数是个整数,并且开端有2个0。以上的d4就是如此,去掉0后数值没变,只是换了一种示意办法。
BigDecimal
能够设置它的scale
,如果精度比原始值低,那么依照指定的办法进行四舍五入或者间接截断:
import java.math.BigDecimal; import java.math.RoundingMode; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.456789"); BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568 BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 间接截断,123.4567 System.out.println(d2);//123.4568 System.out.println(d3);//123.4567 } }
BigDecimal
的加、减、乘、除:
import java.math.BigDecimal; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("124.44"); BigDecimal d2 = new BigDecimal("12.2"); System.out.println(d1.add(d2));//d1+d2 136.64 System.out.println(d1.subtract(d2));//d1-d2 112.24 System.out.println(d1.multiply(d2));//d1*d2 1518.168 System.out.println(d1.divide(d2));//d1/d2 10.2 } }
BigDecimal
在做加、减、乘时,精度不会失落,然而做除法时,存在无奈除尽的状况,这时就必须指定精度以及如何进行截断:
import java.math.BigDecimal; import java.math.RoundingMode; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.456"); BigDecimal d2 = new BigDecimal("23.456789"); BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入 BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽 } }
- 能够对
BigDecimal
做除法的同时求其余数:
import java.math.BigDecimal; public class Demo { public static void main(String[] args) { BigDecimal n = new BigDecimal("22.444"); BigDecimal m = new BigDecimal("0.23"); BigDecimal[] dr = n.divideAndRemainder(m); System.out.println(dr[0]); // 97.0 System.out.println(dr[1]); // 0.134 } }
- 调用
divideAndRemainder()
办法时,返回的数组蕴含两个BigDecimal
,第一个是商,第二个是余数,商总是整数,余数不会大于余数,咱们能够利用该办法判断两个BigDecimal
是否是整数倍数:
BigDecimal n = new BigDecimal("12.34"); BigDecimal m = new BigDecimal("0.12"); BigDecimal[] dr = n.divideAndRemainder(m); if (dr[1].signum() == 0) {//signum()会基于此BigDecimal返回三个值-1、1、0,别离对应为该数小于0,大于0和等于0 // n是m的整数倍 }
- 比拟两个
BigDecimal
的值是否相等时,要留神的是,应用equals()
办法岂但要求两个BigDecimal
的值相等,还要求它们的scale()
相等:
BigDecimal d1 = new BigDecimal("123.45"); BigDecimal d2 = new BigDecimal("123.45000"); System.out.println(d1.equals(d2)); // false,因为scale不同 System.out.println(d1.equals(d2.stripTrailingZeros())); // true,因为d2去除尾部0后scale变为2,与d1雷同
留神:应用compareTo()
来比拟两个BigDecimal
的值,不要用equals()
- 应用
compareTo()
办法来比拟两数大小,它依据两个值的大小别离返回-1、1和0
,别离示意小于、大于和等于。
import java.math.BigDecimal; public class Demo { public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.45"); BigDecimal d2 = new BigDecimal("123.45000"); BigDecimal d3 = new BigDecimal("123.40"); System.out.println(d1.compareTo(d2)); // 0 System.out.println(d1.compareTo(d3));// 1 System.out.println(d3.compareTo(d2));// -1 } }
- 查看
BigDecimal
的源码,能够发现一个BigDecimal
是通过一个BigInteger
和一个scale
来示意的,即BigInteger
示意一个残缺的整数,而scale
示意小数位数:
public class BigDecimal extends Number implements Comparable<BigDecimal> { private final BigInteger intVal; private final int scale; }
更多精彩内容敬请关注微信公众号:【平兄聊Java】