BigDecimal踩过的那些坑,BigDecimal一定不会丢失精度吗?

当需要进行高精度计算时,比如银行系统的money结算,一般都会采用BigDecimal来进行计算,这已经是一个常识了。但是BigDecimal一定不会丢失精度吗?

先看一个例子:

public class Test {
   public static void main(String[] args) {
      BigDecimal value1 = new BigDecimal(0.1);
      BigDecimal value2 = new BigDecimal(0.2);
      System.out.println((value1.add(value2)));
   }
}

输出:

0.3000000000000000166533453693773481063544750213623046875
Process finished with exit code 0

怎么样,是不是很意外?

看下底层注释

 /**
     * Translates a {@code double} into a {@code BigDecimal} which
     * is the exact decimal representation of the {@code double}'s
     * binary floating-point value.  The scale of the returned
     * {@code BigDecimal} is the smallest value such that
     * <tt>(10<sup>scale</sup> &times; val)</tt> is an integer.
     * <p>
     * <b>Notes:</b>
     * <ol>
     * <li>
     * The results of this constructor can be somewhat unpredictable.
     * One might assume that writing {@code new BigDecimal(0.1)} in
     * Java creates a {@code BigDecimal} which is exactly equal to
     * 0.1 (an unscaled value of 1, with a scale of 1), but it is
     * actually equal to
     * 0.1000000000000000055511151231257827021181583404541015625.
     * This is because 0.1 cannot be represented exactly as a
     * {@code double} (or, for that matter, as a binary fraction of
     * any finite length).  Thus, the value that is being passed
     * <i>in</i> to the constructor is not exactly equal to 0.1,
     * appearances notwithstanding.
     *
     * <li>
     * The {@code String} constructor, on the other hand, is
     * perfectly predictable: writing {@code new BigDecimal("0.1")}
     * creates a {@code BigDecimal} which is <i>exactly</i> equal to
     * 0.1, as one would expect.  Therefore, it is generally
     * recommended that the {@linkplain #BigDecimal(String)
     * <tt>String</tt> constructor} be used in preference to this one.
     *
     * <li>
     * When a {@code double} must be used as a source for a
     * {@code BigDecimal}, note that this constructor provides an
     * exact conversion; it does not give the same result as
     * converting the {@code double} to a {@code String} using the
     * {@link Double#toString(double)} method and then using the
     * {@link #BigDecimal(String)} constructor.  To get that result,
     * use the {@code static} {@link #valueOf(double)} method.
     * </ol>
     *
     * @param val {@code double} value to be converted to
     *        {@code BigDecimal}.
     * @throws NumberFormatException if {@code val} is infinite or NaN.
     */
    public BigDecimal(double val) {
        this(val,MathContext.UNLIMITED);
    }

注释里面有说明,如果构造了0.1,其实只能无限接近这个值,但不能完全准确。如果要准确地赋值的话,需要用到输入参数类型为字符串的构造器。

public class Test {
   public static void main(String[] args) {
      BigDecimal value1 = new BigDecimal("0.1");
      BigDecimal value2 = new BigDecimal("0.2");
      System.out.println((value1.add(value2)));
   }
}

输出:

0.3

Process finished with exit code 0

可见,当构造BigDecimal对象时,如果传入的参数不是字符串类型,则计算精度可能出问题。只有构造参数类型为字符串时,才会完全准确。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值