ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

四舍六入计算

2021-06-30 11:32:55  阅读:350  来源: 互联网

标签:六入 return BigDecimal param values value 计算 static 四舍


public final class MathUtil {
  /**
   * PI,比Math.PI多两位
   */
  public static final double PI = 3.1415926535897932384626;

  /**
   * 默认除法运算精度
   */
  private static final int DEFAULT_SCALE = 10;
  private static final double NUM_ROUND = 0.5;

  /**
   * 运算枚举
   */
  private enum MathType {
    /**
     * 加法
     */
    ADD,
    /**
     * 减法
     */
    SUB,
    /**
     * 乘法
     */
    MULTI,
    /**
     * 除法
     */
    DIV
  }

  private MathUtil() {
  }

  /**
   * 转换为{@link java.math.BigDecimal}
   * <p>为保证精度,先转成{@link java.lang.String}然后再用构造函数</p>
   * @param value 数值
   * @return {@link java.math.BigDecimal}
   */
  private static BigDecimal convertToBigDecimal(Number value) {
    return value == null ? BigDecimal.ZERO : new BigDecimal(value.toString());
  }

  /**
   * 提供精确的加法、减法和乘法运算
   * @param type 运算法则
   * @param scale 精确到小数点后几位,只在除法有效
   * @param values 多个值
   * @return 四则运算结果
   */
  private static BigDecimal calculate(MathType type, int scale, Number[] values) {
    if (ArrayUtils.isEmpty(values)) {
      return BigDecimal.ZERO;
    }
    // 第一个数作为被加数、被减数或被乘数
    Number value = values[0];
    BigDecimal result = convertToBigDecimal(value);
    for (int i = 1, l = values.length; i < l; i++) {
      value = values[i];
      if (value != null) {
        switch (type) {
          case ADD:
            result = result.add(convertToBigDecimal(value));
            break;
          case SUB:
            result = result.subtract(convertToBigDecimal(value));
            break;
          case MULTI:
            result = result.multiply(convertToBigDecimal(value));
            break;
          case DIV:
            result = result.divide(convertToBigDecimal(value), scale, RoundingMode.HALF_UP);
            break;
          default:
            break;
        }
      }
    }
    return result;
  }

  /**
   * 提供精确的幂运算
   * @param value 底数
   * @param n 指数
   * @return 幂的积
   */
  public static BigDecimal pow(Number value, int n) {
    return convertToBigDecimal(value).pow(n);
  }

  /**
   * 提供精确的加法运算
   * @param values 多个值的字符串
   * @return 和
   */
  public static BigDecimal add(Number... values) {
    return calculate(MathType.ADD, DEFAULT_SCALE, values);
  }

  /**
   * 提供精确的减法运算
   * @param values 多个值的字符串
   * @return 差
   */
  public static BigDecimal sub(Number... values) {
    return calculate(MathType.SUB, DEFAULT_SCALE, values);
  }

  /**
   * 提供精确的乘法运算
   * @param values 多个值的字符串
   * @return 积
   */
  public static BigDecimal multi(Number... values) {
    return calculate(MathType.MULTI, DEFAULT_SCALE, values);
  }

  /**
   * 提供(相对)精确的除法运算
   * <p>当发生除不尽的情况时,精确到小数点以后10位,以后的数字四舍五入</p>
   * @param values 多个值的字符串
   * @return 商
   */
  public static BigDecimal div(Number... values) {
    return calculate(MathType.DIV, DEFAULT_SCALE, values);
  }

  /**
   * 提供(相对)精确的除法运算
   * <p>当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入</p>
   * @param scale 精确到小数点后几位,只在除法有效
   * @param values 多个值的字符串
   * @return 商
   */
  public static BigDecimal divByScale(int scale, Number... values) {
    if (scale < 0) {
      throw new IllegalArgumentException("The scale must be a positive integer or zero");
    }
    return calculate(MathType.DIV, scale, values);
  }

  /**
   * 四舍六入五成双算法
   * <p>四舍六入五成双是一种比较精确比较科学的计数保留法,是一种数字修约规则。</p>
   * <pre>
   * 算法规则:
   * 四舍六入五考虑,
   * 五后非零就进一,
   * 五后皆零看奇偶,
   * 五前为偶应舍去,
   * 五前为奇要进一。
   * </pre>
   * @param value 需要科学计算的数据
   * @param digit 保留的小数位
   * @return 指定小数位数的数字
   */
  public static BigDecimal round(Number value, int digit) {
    // 小数进位,然后取整计算,再退位得到结果
    BigDecimal ratio = pow(10, digit);
    // 进位后的数字
    BigDecimal number = multi(value, ratio);
    // 获取BigDecimal整数部分,直接舍弃小数部分
    long integer = number.setScale(0, RoundingMode.DOWN).longValue();
    // 获取小数部分
    double decimal = sub(number, integer).doubleValue();
    if (decimal > NUM_ROUND) {
      // 四舍六入
      integer = integer + 1;
    }
    if (decimal == NUM_ROUND && integer % 2 != 0) {
      // 五前为奇要进一
      integer = integer + 1;
    }
    return div(integer, ratio).setScale(digit, RoundingMode.HALF_UP);
  }

  /**
   * 计算阶乘
   * <p>n! = n * (n-1) * ... * end</p>
   * @param n 阶乘起始
   * @param end 阶乘结束
   * @return 结果
   */
  public static BigDecimal factorial(Number n, int end) {
    int st = n.intValue();
    if (st < end) {
      return BigDecimal.ZERO;
    }
    if (st == end) {
      return BigDecimal.ONE;
    }
    return multi(n, factorial(sub(n, 1), end));
  }

  /**
   * 计算阶乘
   * <p>n! = n * (n-1) * ... * 2 * 1</p>
   * @param n 阶乘起始
   * @return 结果
   */
  public static BigDecimal factorial(Number n) {
    return factorial(n, 1);
  }

  /**
   * 计算排列
   * <p>P(n, r) = n!/(n-r)!</p>
   * <p>从n个不同的元素中,取r个不重复的元素,按次序排列</p>
   * @param n 总数
   * @param r 要取出数量
   * @return 排列数
   */
  public static long arrangement(int n, int r) {
    if (n < r) {
      return 0;
    }
    // 对公式约分,实际上是计算了n 到 n-r的阶乘
    return factorial(n, n - r).longValue();
  }

  /**
   * 计算组合
   * <p>C(n, r) = n!/((n-r)! * r!)</p>
   * <p>从n个不同的元素中,取r个不重复的元素,不考虑顺序</p>
   * @param n 总数
   * @param r 要取出数量
   * @return 组合数
   */
  public static long combination(int n, int r) {
    if (n < r) {
      return 0;
    }
    // 组合就是排列的结果再除以r的阶乘
    return div(arrangement(n, r), factorial(r)).longValue();
  }
}

标签:六入,return,BigDecimal,param,values,value,计算,static,四舍
来源: https://blog.csdn.net/qq_40996012/article/details/118357450

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有