Android中数值的精确计算

这篇博客探讨了在Android环境中使用BigDecimal进行高精度数值计算的问题。由于直接使用double构造BigDecimal可能导致精度丢失,作者建议使用String构造方法。CalcUtils工具类展示了如何进行加、减、乘、除操作,并提供了设置舍入模式和保留位数的功能,以确保计算的精确性。文章还详细解释了BigDecimal的舍入模式,如ROUND_UP、ROUND_DOWN等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android中数值计算的精度

Java中有一个类是BigDecimal,该类是专门计算一些要求精度很高的算法,常用于银行金融类的计算,BigDecimal一共有4个够造方法,我们不关心用BigInteger来够造的那两个,那么还有两个, 它们是:

BigDecimal(double val) 
          Translates a double into a BigDecimal. 
BigDecimal(String val) 
          Translates the String repre sentation of a BigDecimal into a BigDecimal.

但是在测试中直接将Double值传进去,也就是调用第一个构造方法来创建的BigDecimal也会损失精度,具体这里先不说了,(完了再看一下源码),因此本人只是利用第二个构造函数来进行对BigDecimal来创建对象的,下面是我写的一个工具类:

/**
 * 
* 功能描述: 用于对数值的精确计算工具类
 *
 */
public class CalcUtils {

    public static final int TYPE_ADD = 0x00; // 加法
    public static final int TYPE_MULTIPLY = 0x01; // 乘法
    public static final int TYPE_DIVIDE = 0x02; // 除法
    public static final int TYPE_SUBTRACT = 0x03; // 减法
   /**
    *  加法
    * @param a 
    * @param b
    * @return
    */
    public static Double add(Double a, Double b) {
        return calc(a, b, -1, TYPE_ADD, null);
    }
    /**
     * 减法
     * @param a
     * @param b
     * @return
     */

    public static Double sub(Double a, Double b) {
        return calc(a, b, -1, TYPE_SUBTRACT, null);
    }
    /**
     * 乘法
     * @param a
     * @param b
     * @return
     */

    public static Double multiply(Double a, Double b) {
        return calc(a, b, -1, TYPE_MULTIPLY, null);
    }
    
    /**
     * 除法
     * @param a
     * @param b
     * @return
     */

    public static Double divide(Double a, Double b) {
        return calc(a, b, -1, TYPE_DIVIDE, null);
    }
 
   /**
    * 乘法
    * @param a
    * @param b
    * @param scale 小数点后保留的位数
    * @param mode 保留的模式
    * @return
    */
    public static Double multiply(Double a, Double b, int scale, RoundingMode mode) {

        return calc(a, b, scale, TYPE_MULTIPLY, mode);
    }
      /**
        * 除法
        * @param a
        * @param b
        * @param scale 小数点后保留的位数
        * @param mode 保留的模式
        * @return
        */
    public static Double divide(Double a, Double b, int scale, RoundingMode mode) {

        return calc(a, b, scale, TYPE_DIVIDE, mode);
    }
     /**
      *  计算
      * @param a
      * @param b
      * @param scale
      * @param type
      * @param mode
      * @return
      */
    private static Double calc(Double a, Double b, int scale, int type, RoundingMode mode) {
        BigDecimal result = null;
        
        BigDecimal bgA = new BigDecimal(String.valueOf(a));
        BigDecimal bgB = new BigDecimal(String.valueOf(b));
        switch (type) {
        case TYPE_ADD:
            result = bgA.add(bgB);
            break;
        case TYPE_MULTIPLY:
            result = bgA.multiply(bgB);
            break;
        case TYPE_DIVIDE:
            try {
                result = bgA.divide(bgB);       
            } catch (ArithmeticException e) {// 防止无限循环而报错  采用四舍五入保留3位有效数字
                result = bgA.divide(bgB,3,RoundingMode.HALF_DOWN);  
            }
        
            break;
        case TYPE_SUBTRACT:
            result = bgA.subtract(bgB);
            break;

        }
        if (mode==null) {
            if(scale!=-1){
              
                result = result.setScale(scale);    
            }
        }else{
            if(scale!=-1){
                result = result.setScale(scale,mode);
            }
        }
        return result.doubleValue();
    }

}

这里涉及到两个参数:Scale和RoundingMode

Scale

scale是用来对利用BigDecimal对数值进行运算后保留的位数。

RouningMode

该参数是BigDecimal是一个枚举类,包含有8个枚举类型,用来说明对经过计算后数值的取舍模式:

ROUND_UP:远离零方向舍入。向绝对值最大的方向舍入,只要舍弃位非0即进位。
ROUND_DOWN:趋向零方向舍入。向绝对值最小的方向输入,所有的位都要舍弃,不存在进位情况。
ROUND_CEILING:向正无穷方向舍入。向正最大方向靠拢。若是正数,舍入行为类似于ROUND_UP,若为负数,舍入行为类似于ROUND_DOWN。Math.round()方法就是使用的此模式。
ROUND_FLOOR:向负无穷方向舍入。向负无穷方向靠拢。若是正数,舍入行为类似于ROUND_DOWN;若为负数,舍入行为类似于ROUND_UP。
HALF_UP:最近数字舍入(5进)。这是我们最经典的四舍五入。
HALF_DOWN:最近数字舍入(5舍)。在这里5是要舍弃的。
HAIL_EVEN:银行家舍入法。
Android 精确计算工具类。 /** * @Title: Arith.java * @Package com.uxun.pay.util * @Description: TODO(用一句话描述该文件做什么) * @author daiw * @date 2016-1-5 上午9:05:34 * @version V1.0 */ package com.xwtec.commonutil; import java.math.BigDecimal; /** * Arith * (由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精确的浮点数运算,包括加减乘除和四舍五入) * @author chenke * @time 2017/12/5 16:22 * @mail ch_chenke@163.com */ public class Arith { //默认除法运算精度 private static final int DEF_DIV_SCALE = 10; //这个类不能实例化 private Arith() { } /** * 提供精确的String转换成double * @param v * @return */ public static double strPreDou(String v) { BigDecimal b = new BigDecimal(v); return b.doubleValue(); } /** * 提供精确的加法运算。 * @param v1 被加数 * @param v2 加数 * @return 两个参数的和 */ public static double add(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); 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); } /** * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 * 定精度,以后的数字四舍五入。 * @param v1 被除数 * @param v2 除数 * @param scale 表示表示需要精确到小数点以后几位。 * @return 两个参数的商 */ public 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)); return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 提供精确的小数位四舍五入处理。 * @param v 需要四舍五入的数字 * @param scale 小数点后保留几位 * @return 四舍五入后的结果 */ public static double round(double v, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b = new BigDecimal(Double.toString(v)); BigDecimal BigDecimal("1"); return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值