1. ホーム
  2. Java

BigDecimalのサイズ比較メモ(イコール)

2022-02-28 19:41:44

プロジェクトでBigDecimalのequalsメソッドを使用してサイズを比較すると、結果が真でないことがあります。

    public static void main(String[] args) {
        BigDecimal a = new BigDecimal(0.00);
        BigDecimal b = new BigDecimal(0);

        boolean result = a.equals(b);
        System.out.println("a equals b -->" + result);

        BigDecimal c = new BigDecimal("0.00");
        BigDecimal d = new BigDecimal("0");

        boolean result1 = c.equals(d);
        System.out.println("c equals d -->" + result1);
    }

結果

a equals b -->true
c equals d -->false

aとbは真の比較になり、cとdはfasleの比較になることがわかります。

c と d は、入力される文字列 (データベースクエリの値に相当) のコンストラクタを使用します。

プロジェクトでデータベースからの値(上の例ではc, d)を比較すると、明らかに期待した結果にはならないので、次のような方法に修正しました。

boolean result2 = c.compareTo(d) == 0;
System.out.println("c compareTo d -->" + result2);

結果

c compareTo d -->true

コンストラクタを見てみましょう。

    public BigDecimal(String val) {
        this(val.toCharArray(), 0, val.length());
    }

このコンストラクタに対するコメントです。

コンストラクタに "0" が渡され、0 を取得していることがわかります。 は小数点以下がない を含む 0.00 を得るために、コンストラクタに "0.00" が渡されます。 小数点以下2桁

もう一度、イコールメソッドについて見てみましょう。

 @Override
    public boolean equals(Object x) {
        if (! (x instanceof BigDecimal))
            return false;
        BigDecimal xDec = (BigDecimal) x;
        if (x == this)
            return true;
        if (scale ! = xDec.scale)
            return false;
        long s = this.intCompact;
        long xs = xDec.intCompact;
        if (s ! = INFLATED) {
            if (xs == INFLATED)
                xs = compactValFor(xDec.intVal);
            return xs == s;
        } else if (xs ! = INFLATED)
            return xs == compactValFor(this.intVal);

        return this.inflated().equals(xDec.inflated());
    }

equals メソッドで小数点以下の桁数を比較していることがよくわかりますね ----->  if (scale ! = xDec.scale) はfalseを返します。 

ここで、上記のC, Dequalsの比較結果がなぜfalseになるのかがわかります。

compareTo メソッドを見てみましょう。

/**
     * Compares this {@code BigDecimal} with the specified
     * {@code BigDecimal}.  Two {@code BigDecimal} objects that are
     Two {@code BigDecimal} objects that are * equal in value but have a different scale (like 2.0 and 2.00) * are considered equal by this method.
     Two {@code BigDecimal} objects that are * equal in value but have a different scale (like 2.0 and 2.00) * are considered equal by this method.
     This method is provided * in preference to individual methods for each of the six boolean
     * comparison operators ({@literal <}, ==,
     * {@literal >}, {@literal >=}, ! =, {@literal <=}).  The
     * suggested idiom for performing these comparisons is:
     * {@code (x.compareTo(y)} &lt;<i>op</i>&gt; {@code 0)}, where
     * &lt;<i>op</i>&gt; is one of the six comparison operators.
     *
     * @param val {@code BigDecimal} to which this {@code BigDecimal} is
     * to be compared.
     * @return -1, 0, or 1 as this {@code BigDecimal} is numerically
     * less than, equal to, or greater than {@code val}.
     */
    public int compareTo(BigDecimal val) {
        // Quick path for equal scale and non-inflated case.
        if (scale == val.scale) {
            long xs = intCompact;
            long ys = val.intCompact;
            if (xs ! = INFLATED && ys ! = INFLATED)
                return xs ! = ys ? ((xs > ys) ? 1 : -1) : 0;
        }
        int xsign = this.signum();
        int ysign = val.signum();
        if (xsign ! = ysign)
            return (xsign > ysign) ? 1 : -1;
        if (xsign == 0)
            return 0;
        int cmp = compareMagnitude(val);
        return (xsign > 0) ? cmp : -cmp;
    }

ご覧のように、小数点以下の桁数が同じ場合と、異なる場合があります。そこで、小数点以下の桁数が同じかどうか、2つの数値を比較します。