• BigDecimal初始化不要用double类型


    在进行单价、总价相关的计算时,就会用到BigDecimal。
    在初始化时,一个不小心,就可能给自己挖坑。

    示例如下:

    public class BigDecimalInitTest {
        public static void main(String[] args) {
            BigDecimal amount1=new BigDecimal("0.06");
            BigDecimal amount2=new BigDecimal(0.06);
            System.out.println(amount1);
            System.out.println(amount2);
        }
    }
    

    运行之后,结果为:

    0.06
    0.059999999999999997779553950749686919152736663818359375
    

    源码注释

    打开BigDecimal的构造方法,可以发现:

       /**
         * 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);
        }
    

    大体意思就是,BigDecimal(double val)这个构造方法有时是无法精确预料的,
    传入0.1,有可能变成0.1000000000000000055511151231257827021181583404541015625。
    因为double类型无法精确地存储0.1

    IDEA编码提示

    IDEA也会在编码时给出提示。

    结论

    通过double类型初始化的BigDecimal类型,是不精确的。
    最好用String类型的数值字符串来初始化。

  • 相关阅读:
    AQS笔记二 ---- 使用AQS自定义锁
    AQS笔记一 --- 源码分析
    ElasticSearch(二十一)正排和倒排索引
    ElasticSearch(二十)定位不合法的搜索及其原因
    ElasticSearch(十八)初识分词器
    ElasticSearch(十七)初识倒排索引
    还在用 kill -9 停机?这才是最优雅的姿势(转)
    一文快速搞懂MySQL InnoDB事务ACID实现原理(转)
    你真的理解零拷贝了吗?(转)
    关于分布式事务的读书笔记
  • 原文地址:https://www.cnblogs.com/expiator/p/11450684.html
Copyright © 2020-2023  润新知