Java之浮点类型的种种悬疑

       浮点类型(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的值相等。

扫描二维码关注公众号,回复: 2645239 查看本文章

以上内容采自《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 后的四舍五入  
    }  
  
}  

猜你喜欢

转载自blog.csdn.net/BushQiang/article/details/80463034
今日推荐