如何处理浮点数的精度问题

2025-05-09 02:45:05
推荐回答(1个)
回答1:

您好,很高兴为您解答。

 一般对double类型进行运算时,做好对结果进行处理,然后拿这个值去做其他事情。 下面我们就用代码来说明一下如何对浮点数进行精度计算,以double为例。

/*
 * Copyright reserved 2010 by AllensLab
 * @project AllensLab
 * @date Feb 22, 2010
 */
package cn.allen.tools;

import java.math.BigDecimal;

/**
 * RoundTool
 * @author allen
 * @time 10:05:40 AM Feb 22, 2010
 */
public class RoundTools {
    /**  
     * 对double数据进行取精度.  
     * 

  
     * For example: 
  
     * double value = 100.345678; 
  
     * double ret = round(value,4,BigDecimal.ROUND_HALF_UP); 
  
     * ret为100.3457 
  
     *   
     * @param value  
     *            double数据.  
     * @param scale  
     *            精度位数(保留的小数位数).  
     * @param roundingMode  
     *            精度取值方式.  
     * @return 精度计算后的数据.  
     */
    public static double round(double value, int scale, int roundingMode) {
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(scale, roundingMode);
        double d = bd.doubleValue();
        bd = null;
        return d;
    }
    
    public static BigDecimal roundAgain(double value, int scale, int roundingMode) {
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(scale, roundingMode);
        return bd;
    }
    
    /* 用于加、减、乘和除的方法给 BigDecimal 值提供了算术运算。由于 BigDecimal 对象是不可变的,这些方法中的每一个都会产生新的 BigDecimal 对象。
     * 因为创建对象的开销, BigDecimal 不适合于大量的数学计算,但设计它的目的是用来精确地表示小数。 */
    
    /**
     * Addition
     * @param number1
     * @param number2
     * @return
     * @author allen
     * @date 10:42:47 AM Feb 22, 2010
     */
    public static double add(double number1, double number2, int newScale, int roundingMode) {
        return BigDecimal.valueOf(number1).add(BigDecimal.valueOf(number2)).setScale(newScale, roundingMode).doubleValue();
    }
    
    public static double add(int newScale, int roundingMode, double number1, double numbers) {
        BigDecimal bd = new BigDecimal(number1);
        for (double number : numbers) {
            bd = bd.add(BigDecimal.valueOf(number).setScale(newScale, roundingMode));
        }
        return bd.doubleValue();
    }
    
    /**
     * Subtraction
     * @param number1
     * @param number2
     * @return
     * @author allen
     * @date 10:45:36 AM Feb 22, 2010
     */
    public static double subtract(double number1, double number2, int newScale, int roundingMode) {
        return BigDecimal.valueOf(number1).subtract(BigDecimal.valueOf(number2)).setScale(newScale, roundingMode).doubleValue();
    }
    
    /**
     * Multiplication 
     * @param number1
     * @param number2
     * @return
     * @author allen
     * @date 10:46:23 AM Feb 22, 2010
     */
    public static double multiply(double number1, double number2, int newScale, int roundingMode) {
        return BigDecimal.valueOf(number1).multiply(BigDecimal.valueOf(number2)).setScale(newScale, roundingMode).doubleValue();
        
    }
    
    /**
     * Division
     * 尽量采用财务常用的四舍六入五取偶 即ROUND_HALF_EVEN
     * @param number1
     * @param number2
     * @return
     * @author allen
     * @date 10:47:12 AM Feb 22, 2010
     */
    public static double divide(double number1, double number2, int scale, int roundingMode) {
        return BigDecimal.valueOf(number1).divide(BigDecimal.valueOf(number2), scale, roundingMode).doubleValue();
    }
    
    /**  
     * 测试用的main方法.  
     *   
     * @param args  
     *            运行参数.  
     */
    public static void main(String[] args) {
        //下面都以保留2位小数为例   
        System.out.println(add(12.341, 12.3449, 2, BigDecimal.ROUND_HALF_EVEN));
        System.out.println(add(2, BigDecimal.ROUND_HALF_UP, 12.346, 12.3449, 12.3401, 12.345));
        System.out.println(subtract(12.3449, 12.341, 2, BigDecimal.ROUND_HALF_EVEN));
        System.out.println(multiply(12.3449, 0.01, 2, BigDecimal.ROUND_HALF_UP));
        System.out.println(divide(11.341, 12.346, 2, BigDecimal.ROUND_HALF_EVEN));
        //ROUND_UP   
        //只要第2位后面存在大于0的小数,则第2位就+1
        System.out.println("-- ROUND_UP -- 只要第2位后面存在大于0的小数,则第2位就+1 --");
        System.out.println(round(12.3401, 2, BigDecimal.ROUND_UP));//12.35   
        System.out.println(round(-12.3401, 2, BigDecimal.ROUND_UP));//-12.35   
        //ROUND_DOWN   
        //与ROUND_UP相反   
        //直接舍弃第2位后面的所有小数   
        System.out.println("-- ROUND_DOWN -- 直接舍弃第2位后面的所有小数 --");
        System.out.println(round(12.349, 2, BigDecimal.ROUND_DOWN));//12.34   
        System.out.println(round(-12.349, 2, BigDecimal.ROUND_DOWN));//-12.34   
        //ROUND_CEILING   
        //如果数字>0 则和ROUND_UP作用一样   
        //如果数字<0 则和ROUND_DOWN作用一样   
        System.out.println("-- OUND_CEILING -- 如果数字>0 则和ROUND_UP作用一样 如果数字<0 则和ROUND_DOWN作用一样 --");
        System.out.println(round(12.3401, 2, BigDecimal.ROUND_CEILING));//12.35   
        System.out.println(round(-12.349, 2, BigDecimal.ROUND_CEILING));//-12.34   
        //ROUND_FLOOR   
        //如果数字>0 则和ROUND_DOWN作用一样   
        //如果数字<0 则和ROUND_UP作用一样   
        System.out.println("-- ROUND_FLOOR -- 如果数字>0 则和ROUND_DOWN作用一样 如果数字<0 则和ROUND_UP作用一样 --");
        System.out.println(round(12.349, 2, BigDecimal.ROUND_FLOOR));//12.34   
        System.out.println(round(-12.3401, 2, BigDecimal.ROUND_FLOOR));//-12.35   
        //ROUND_HALF_UP [这种方法最常用]   
        //如果第3位数字>=5,则第2位数字+1   
        //备注:只看第3位数字的值,不会考虑第3位之后的小数的   
        System.out.println("-- ROUND_HALF_UP -- 如果第3位数字>=5,则第2位数字+1 --");
        System.out.println(round(12.345, 2, BigDecimal.ROUND_HALF_UP));//12.35   
        System.out.println(round(12.3449, 2, BigDecimal.ROUND_HALF_UP));//12.34   
        System.out.println(round(-12.345, 2, BigDecimal.ROUND_HALF_UP));//-12.35   
        System.out.println(round(-12.3449, 2, BigDecimal.ROUND_HALF_UP));//-12.34   
        //ROUND_HALF_DOWN   
        //如果第3位数字>=5,则做ROUND_UP   
        //如果第3位数字<5,则做ROUND_DOWN   
        System.out.println("-- ROUND_HALF_DOWN -- 如果第3位数字>=5,则做ROUND_UP,如果第3位数字<5,则做ROUND_DOWN --");
        System.out.println(round(12.345, 2, BigDecimal.ROUND_HALF_DOWN));//12.35   
        System.out.println(round(12.3449, 2, BigDecimal.ROUND_HALF_DOWN));//12.34   
        System.out.println(round(-12.345, 2, BigDecimal.ROUND_HALF_DOWN));//-12.35   
        System.out.println(round(-12.3449, 2, BigDecimal.ROUND_HALF_DOWN));//-12.34   
        //ROUND_HALF_EVEN   
        //如果第3位是偶数,则做ROUND_HALF_DOWN   
        //如果第3位是奇数,则做ROUND_HALF_UP   
        System.out.println("-- ROUND_HALF_EVEN -- 如果第3位是偶数,则做ROUND_HALF_DOWN,如果第3位是奇数, 则做ROUND_HALF_UP --");
        System.out.println(round(12.346, 2, BigDecimal.ROUND_HALF_EVEN));//12.35   
        System.out.println(round(12.345, 2, BigDecimal.ROUND_HALF_EVEN));//12.35   
    }
}


如若满意,请点击右侧【采纳答案】,如若还有问题,请点击【追问】

希望我的回答对您有所帮助,望采纳!

                                                                                                                            ~ O(∩_∩)O~