浮点类型(float和double)是我们非常熟悉的类型,在程序中也会经常使用,如用来表示增长率,物品重量等方面。不过在使用浮点类型时,还是要留意一些问题的。毕竟浮点类型仅是数学中小数的一种模拟,不能将其与数学中的小数运算等同视之。
浮点类型只是近似的存储
例如0.1+0.2得到的结果并不是0.3:
public class Main {
public static void main(String[] args){
double d1=0.1;
double d2=0.2;
System.out.println(d1+d2);
}
}
其实这并不是计算错误,这只是浮点类型存储的问题。计算机使用二进制来存储数据,而很多小数都不能够准确的使用二进制来表示,就像使用十进制小数不能准确的表示1/3这样的分数一样。
数量极差很大的浮点运算
/**
*
* @Description :浮点类型运算
* @author Bush罗
* @date 2018年5月26日
*
*/
public class Main {
public static void main(String[] args){
float f1=30000;
float f2=f1+1;
System.out.println("f1="+f1+",f2="+f2);
if(f1<f2){
System.out.println("f1<f2成立");
}else{
System.out.println("意外发生,f1<f2不成立!");
}
float f3=30000000;
float f4=f3+1;
System.out.println("f3="+f3+",f4="+f4);
if(f3<f4){
System.out.println("f3<f4成立");
}else{
System.out.println("意外发生,f3<f4不成立!");
}
}
}
意外发生了,f1与f2的比较没有问题,但是f3与f4的比较却发生了问题,从结果来看f3+1并没有改变f3的值
这是由于浮点之的存储造成的,二进制所能表示的两个相邻的浮点值间存在一定的间隔,浮点值越大,这个间隙也会越大,当浮点值大到一定程度时,如果对浮点值的改变很小,就不足以使浮点值发生变化,这就好比大海蒸发了一滴水,但还是大海,几乎没有变化。因此在本程序中,f3+1与f3的值相等。
以上内容采自《java深入解析》
float ,double 只能用来做科学计算或者工程计算,但在商业计算中要用java.math.BigDecimal
BigDecimal类可以实现浮点数的精确计算
import java.math.BigDecimal;
/**
*
* @Description :BigDecimal实现精确的加减乘除
* @author Bush罗
* @date 2018年5月26日
*
*/
public class Main {
// 默认除法运算精度,如果除不尽保留10位
private static final int DEF_DIV_SCALE = 10;
/**
* 精确的加法运算
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));// 建议写string类型的参数,下同
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 精确的减法运算
* @param v1
* @param v2
* @return
*/
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
*
* 提供精确的乘法运算
* @param v1
* @param v2
* @return
*/
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
*
* 提供相对精确的除法运算,当发生除不尽的情况,精确到.后10位
* @param v1
* @param v2
* @return
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}
private static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(" the scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
/**
* ROUND_HALF_UP: 遇到.5的情况时往上近似,例: 1.5 ->;2
*
*/
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();// scale 后的四舍五入
}
}