android不在坑三:Float丢失精度

android不在坑三:Float丢失精度

前言:

测试:你这个平均数,怎么一下正确一下错误,你让我怎么测啊!

面对测试的怒吼,赶快灰溜溜的检查代码去了。没错啊,最后测试for循环了几次才发现,日!怎么会这样,这不是坑么

后面开发商城的时候,基本全用String来,用BigDecimal进行精确运算

当然看看测试,float是怎么丢失精度的

public class Test_1 {
    public static void main(String[] args) {
        System.out.println(0.06+0.01);
        System.out.println(1.0-0.42);
        System.out.println(4.015*100);
        System.out.println(303.1/1000);
    }
}

运行结果如下。

     0.06999999999999999

     0.5800000000000001

     401.49999999999994

     0.30310000000000004

你认为你看错了,但结果却是是这样的。问题在哪里呢?原因在于我们的计算机是二进制的。浮点数没有办法是用二进制进行精确表示。我们的CPU表示浮点数由两个部分组成:指数和尾数,这样的表示方法一般都会失去一定的精确度,有些浮点数运算也会产生一定的误差。如:2.4的二进制表示并非就是精确的2.4。反而最为接近的二进制表示是 2.3999999999999999。浮点数的值实际上是由一个特定的数学公式计算得到的。

其实java的float只能用来进行科学计算或工程计算,在大多数的商业计算中,一般采用java.math.BigDecimal类来进行精确计算。

好啦,送上大力丸工具类一枚。

public class DecimalUtil {

  /**
   * 金钱加法
   */
  public static String add(String v1, String v2) {
    BigDecimal b1 = new BigDecimal(v1);
    BigDecimal b2 = new BigDecimal(v2);

    return b1.add(b2).toString();
  }

  /**
   * 金钱乘法
   */
  public static String multiply(String v1, String v2) {
    BigDecimal b1 = new BigDecimal(v1);
    BigDecimal b2 = new BigDecimal(v2);

     return b1.multiply(b2).toString();
  }

  /**
   * 乘法
   *
   * @param v1 乘数
   * @param v2 被乘数
   * @param scale 小数点保留位数
   */
  public static String multiplyWithScale(String v1, String v2, int scale) {
    BigDecimal b1 = new BigDecimal(v1);
    BigDecimal b2 = new BigDecimal(v2);
    BigDecimal result = b1.multiply(b2);
    result = result.setScale(scale);
    return result.toString();
  }

  /**
   * 金钱除法
   */
  public static String divide(String v1, String v2) {
    BigDecimal b1 = new BigDecimal(v1);
    BigDecimal b2 = new BigDecimal(v2);

    return b1.divide(b2).toString();
  }

  /**
   * 如果除不断,产生无限循环小数,那么就会抛出异常,解决方法就是对小数点后的位数做限制
   *
   * @param v2 小数模式 ,DOWN,表示直接不做四舍五入,参考{@link RoundingMode}
   */
  public static String divideWithRoundingDown(String v1, String v2) {
return divideWithRoundingMode(v1, v2, RoundingMode.DOWN);
  }

  /** 选择小数部分处理方式 */
  public static String divideWithRoundingMode(String v1, String v2, RoundingMode roundingMode) {
     return divideWithRoundingModeAndScale(v1, v2, RoundingMode.DOWN, 0);
  }

  /**
   * 选择小数点后部分处理方式,以及保留几位小数
   *
   * @param v1 除数
   * @param v2 被除数
   * @param roundingMode 小数处理模式
   * @param scale 保留几位
   */
  public static String divideWithRoundingModeAndScale(String v1, String v2,
  RoundingMode roundingMode, int scale) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, scale, roundingMode).toString();
  }

  /**
   * 金钱减法
   */
  public static String subtract(String v1, String v2) {
    BigDecimal b1 = new BigDecimal(v1);
    BigDecimal b2 = new BigDecimal(v2);

    return b1.subtract(b2).toString();
  }
}

使用方法:

乘法:

 String countIntegral = DecimalUtil.multiply(integral, num);

加法:

    String selectedMoney = DecimalUtil.add(selectedMoney, countMoney);

结语:最后记得传入参数不能为空,即初始值要为0, String num="0",不然会报错

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值