打赏

java和js精确运算

public class ArithUtil {
    /**
     * 加法
     * @param 
     * @return double
     * @throws Exception
     * @author zhangyn
     * @date 2017年6月7日 下午6:33:30
     */
    public static double add(double value1, double value2) {
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.add(b2).doubleValue();
    }
    
    /**
     * 减法
     * @param value1 减数
     * @param value2 被减数
     * @return  double
     * @throws  Exception
     * @author  zhangyn
     * @date    2017年6月9日 下午3:29:30
     */
    public static double sub(double value1,double value2){
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.subtract(b2).doubleValue();
    }
    
    /**
     * 乘法
     * @param
     * @return double
     * @throws Exception
     * @author zhangyn
     * @date 2017年6月7日 下午6:33:49
     */
    public static double mul(double value1, double value2) {
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.multiply(b2).doubleValue();
    }
    
     /**
     * 提供精确的除法运算方法div
     * @param value1 被除数
     * @param value2 除数
     * @param scale 精确范围,必须大于0
     * @return 两个参数的商
     * @throws IllegalAccessException
     */
    public static double div(double value1,double value2,int scale) throws IllegalAccessException{
        //如果精确范围小于0,抛出异常信息
        if(scale<0){         
            throw new IllegalAccessException("精确度不能小于0");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.divide(b2, scale).doubleValue();    
    }
    
    /** 两个double比较或者金额比较,建议小数点后保留两位
      * @Description ArithUtil.java    
      * @param value1
      * @param value2
      * @return -1 是不相等 0:相等
      * @throws Exception                    
      * @author liz
      * @date 2017年6月28日下午4:22:34
     */
    public static int doubleCompare(String value1,String value2) throws Exception{
        if(GenericValidator.isBlankOrNull(value1) || GenericValidator.isBlankOrNull(value2)){
            return -1;
        }else{
            return new BigDecimal(value1).compareTo(new BigDecimal(value2));
        }
        
    }
    
    
    /**
     * 整数加法的精确运算
     * @param
     * @return  int
     * @throws  Exception
     * @author  zhangyn
     * @date    2017年6月26日 下午6:58:04
     */
    public static int addint(int value1, int value2) {
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.add(b2).intValue();
    }
    
    /**
     * 整数减法的精确运算
     * @param value1 减数
     * @param value2 被减数
     * @return  int
     * @throws  Exception
     * @author  zhangyn
     * @date    2017年6月26日 下午6:59:27
     */
    public static int subint(int value1,int value2){
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.subtract(b2).intValue();
    }
    
    /**
     * 整数乘法精确运算
     * @param
     * @return  int
     * @throws  Exception
     * @author  zhangyn
     * @date    2017年6月26日 下午7:01:58
     */
    public static int mulint(int value1, int value2) {
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.multiply(b2).intValue();
    }
    
     /**
     * 整数除法精确运算
     * @param value1 被除数
     * @param value2 除数
     * @param scale 精确范围,必须大于0
     * @return 两个参数的商
     * @throws IllegalAccessException
     * @date    2017年6月26日 下午7:02:58
     */
    public static int divint(int value1,int value2,int scale) throws IllegalAccessException{
        //如果精确范围小于0,抛出异常信息
        if(scale<0){         
            throw new IllegalAccessException("精确度不能小于0");
        }
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.divide(b2, scale).intValue();    
    }
}
View Code

 为什么不直接四则运算呢?换句话说计算机计算机为什么有精度损失呢?

以下内容摘自百度百科@二进制

大家知道的,计算机以二进制存储数据,精度损失就发生在十进制转二进制的时候

计算机中的十进制小数转换二进制
计算机中的十进制小数用二进制通常是用乘二取整法来获得的。
比如0.65换算成二进制就是:
0.65 × 2 = 1.3 取1,留下0.3继续乘二取整
0.3 × 2 = 0.6 取0, 留下0.6继续乘二取整
0.6 × 2 = 1.2 取1,留下0.2继续乘二取整
0.2 × 2 = 0.4 取0, 留下0.4继续乘二取整
0.4 × 2 = 0.8 取0, 留下0.8继续乘二取整
0.8 × 2 = 1.6 取1, 留下0.6继续乘二取整
0.6 × 2 = 1.2 取1,留下0.2继续乘二取整
.......
一直循环,直到达到精度限制才停止(所以,计算机保存的小数一般会有误差,所以在编程中,要想比较两个小数是否相等,只能比较某个精度范围内是否相等。)。这时,十进制的0.65,用二进制就可以表示为:01010011。
 
20200824:js精确运算:
原文:
/**
 * 加法函数,用来得到精确的加法结果
 * @param {Object} arg1
 * @param {Object} arg2
 */
function accAdd(arg1, arg2) {
    var r1 = deal(arg1);
    var r2 = deal(arg2);
    var m = Math.pow(10, Math.max(r1, r2))
    return(arg1 * m + arg2 * m) / m
}

/**
 * 乘法函数,用来得到精确的乘法结果
 * @param {Object} arg1
 * @param {Object} arg2
 */
function accMul(arg1, arg2) {
    var m = 0;
    m += deal(arg1);
    m += deal(arg2);
    var r1 = Number(arg1.toString().replace(".", ""));
    var r2 = Number(arg2.toString().replace(".", ""));
    return(r1 * r2) / Math.pow(10, m)
}

/**
 * 除法函数,用来得到精确的除法结果
 * @param {Object} arg1
 * @param {Object} arg2
 */
function accDiv(arg1, arg2) {
    var t1 = deal(arg1);
    var t2 = deal(arg2);
    var r1 = Number(arg1.toString().replace(".", ""))
    var r2 = Number(arg2.toString().replace(".", ""))
    return(r1 / r2) * Math.pow(10, t2 - t1);
}
/**
 * 求小数点后的数据长度
 */
function deal(arg) {
    var t = 0;
    try {
        t = arg.toString().split(".")[1].length
    } catch(e) {}
    return t;
}
View Code

 我用到了加法,简单的依靠参考博客的文章,点个几次可能发现没问题,再多点几次再多点几次,你会发现还有问题,我出现的问题是场景是减法时依旧会出现精度问题,研究了一下,是下面的代码导致的

 return(arg1 * m + arg2 * m) / m

主要原因是乘法时出现了错误,比如当0.07*100时出现了,7.0(此处省略N个0)01

所以这一步,你还需要用到博客中的乘法

改进版:

/**
 * 加法函数,用来得到精确的加法结果。千万别问减法怎么做,如果自己不能写出来赶紧脱坑
 * @param {Object} arg1
 * @param {Object} arg2
 */
function accAdd(arg1, arg2) {
    var r1 = deal(arg1);
    var r2 = deal(arg2);
    var m = Math.pow(10, Math.max(r1, r2))
    return(accMul(arg1 , m) + accMul(arg2 , m)) / m
}

/**
 * 乘法函数,用来得到精确的乘法结果
 * @param {Object} arg1
 * @param {Object} arg2
 */
function accMul(arg1, arg2) {
    var m = 0;
    m += deal(arg1);
    m += deal(arg2);
    var r1 = Number(arg1.toString().replace(".", ""));
    var r2 = Number(arg2.toString().replace(".", ""));
    return(r1 * r2) / Math.pow(10, m)
}

/**
 * 除法函数,用来得到精确的除法结果
 * @param {Object} arg1
 * @param {Object} arg2
 */
function accDiv(arg1, arg2) {
    var t1 = deal(arg1);
    var t2 = deal(arg2);
    var r1 = Number(arg1.toString().replace(".", ""))
    var r2 = Number(arg2.toString().replace(".", ""))
    return(r1 / r2) * Math.pow(10, t2 - t1);
}
/**
 * 求小数点后的数据长度
 */
function deal(arg) {
    var t = 0;
    try {
        t = arg.toString().split(".")[1].length
    } catch(e) {}
    return t;
}
View Code

 

posted @ 2017-07-06 15:15  每天都要学一点  阅读(245)  评论(0编辑  收藏  举报