数值修约算法

发布时间 2023-07-17 18:11:23作者: 风中萧萧

1、Java版本

点击查看代码
import com.github.pagehelper.util.StringUtil;
import static cn.hutool.core.convert.Convert.toStr;
import static org.springframework.util.ObjectUtils.isEmpty;

/**
     * 数值、精度、修约规则
     * <pre>
     *     实例代码:
     *     System.out.println(evenRound(1.1345, 0.001, "四舍五入"));
     *     System.out.println(evenRound(1.1345, 0.001, "四舍六入"));
     * </pre>
     *
     * @param value:数值
     * @param places:精度(1、0.5、10、0.1、0.01...)
     * @param even:修约(四舍五入、四舍六入)
     * @return {BigDecimal}
     */
    public static String evenRound(Object value, Object places, Object even) {
        if (places == null || even == null) {
            String value2 = toStr(value);
            return value2;
        }
        String value2 = toStr(value);
        String places2 = toStr(places);
        String even2 = toStr(even);
        //数值和精度 不可以为空
        if (StringUtil.isEmpty(value2) || StringUtil.isEmpty(places2) || StringUtil.isEmpty(even2)) return value2;
        try {
            BigDecimal num = new BigDecimal(value2);
            Integer decimalPlaces = 0;
            //默认是 四舍六入
            Integer evenRound = (even2.indexOf("五") > -1 || even2.indexOf("5") > -1 || even2.indexOf("伍") > -1) ? 5 : 6;

            if (places2.equals("0.5")) {
                //TODO 精度为 0.5 时
                //(0.75 * 2).修约 / 2
                BigDecimal rule = new BigDecimal("2");//系数
                //保留0位小数
                decimalPlaces = 0;
                if (evenRound == 5) {
                    //四舍五入
                    value2 = ((num.multiply(rule)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).divide(rule, 4, BigDecimal.ROUND_HALF_UP)).toString();
                } else {
                    //四舍六入
                    value2 = ((num.multiply(rule)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN).divide(rule, 4, BigDecimal.ROUND_HALF_EVEN)).toString();
                }
                value2 = numDecimal(value2, 1);
            } else if (places2.equals("5")) {
                //TODO 精度为 ”5“ 时 ,个位只有(0 | 5)
                //(0.75 * 0.2).修约 / 0.2
                BigDecimal rule = new BigDecimal("0.2");//系数
                //保留0位小数
                decimalPlaces = 0;
                if (evenRound == 5) {
                    //四舍五入
                    value2 = ((num.multiply(rule)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).divide(rule, 4, BigDecimal.ROUND_HALF_UP)).toString();
                } else {
                    //四舍六入
                    value2 = ((num.multiply(rule)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN).divide(rule, 4, BigDecimal.ROUND_HALF_EVEN)).toString();
                }
                value2 = numDecimal(value2, 0);
            } else if (places2.equals("10")) {
                //TODO 精度为 ”10“ 时
                //(0.75 / 10).修约 * 10
                BigDecimal rule = new BigDecimal("10");//系数
                //保留0位小数
                decimalPlaces = 0;
                if (evenRound == 5) {
                    //四舍五入
                    value2 = ((num.divide(rule)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).multiply(rule)).toString();
                } else {
                    //四舍六入
                    value2 = ((num.divide(rule)).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN).multiply(rule)).toString();
                }
            } else {
                //0.1、0.01
                String[] split = places2.split("\\.");//截取小数点
                if (split.length > 1) {
                    //拿到小数点后几位,就保留几位小数
                    decimalPlaces = split[1].length();
                }
                if (evenRound == 5) {
                    //四舍五入
                    value2 = num.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).toString();
                } else {
                    //四舍六入
                    value2 = num.setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN).toString();
                }
                value2 = numDecimal(value2, decimalPlaces);
            }
        } catch (Exception e) {
            System.err.println(value + "," + places + "," + even + "\t修约规则有误:" + e.getMessage());
        }
        return value2;
        //规则:
        //四舍六入五考虑,
        //五后非零就进一,
        //五后皆零看奇偶,
        //五前为偶应舍去,
        //五前为奇要进一。
    }

    /**
     * 小数位不够自动补 “0”
     *
     * @param num {数值}
     * @param len {保留几位小数}
     */
    public static String numDecimal(String num, int len) {
        num = org.springframework.util.ObjectUtils.isEmpty(num) ? "0" : toStr(num);
        len = org.springframework.util.ObjectUtils.isEmpty(len) ? 0 : len;
        if (len == 0) return num.split("\\.")[0];
        String decimal;
        if (num.indexOf(".") == -1 && len != 0) num += ".0";
        String[] split = num.split("\\.");
        decimal = split[1];//12
        num = split[0];
        if (decimal.length() > len) {
            decimal = decimal.substring(0, len);
        } else {
            while (decimal.length() != len) {
                decimal += "0";
            }
        }
        return num + "." + decimal;
    }

2、JavaScript版本

点击查看代码
/**
 * 数值修约算法(四舍六入)
 * @param num
 * @param decimalPlaces{number}
 * @returns {number}
 * @see https://www.jianshu.com/p/d329fe017520
 */
export function sixRound(num, decimalPlaces) {
  let d = decimalPlaces || 0;
  let m = Math.pow(10, d);
  let n = +(d ? num * m : num).toFixed(8);
  let i = Math.floor(n), f = n - i;
  let e = 1e-8;
  let r = (f > 0.5 - e && f < 0.5 + e) ?
    ((i % 2 === 0) ? i : i + 1) : Math.round(n);
  return d ? r / m : r;
}