如何统一解析字符串到BigDecimal?

时间:2015-10-30 16:18:08

标签: java parsing bigdecimal

我将字符串作为程序的输入,但这些可以用各种格式表示。 E.g:

  • 8900
  • 8.9E + 3
  • 89E + 2
  • 8900.000

所有这些数字在数学上,以下程序也会说明匹配:

public class BigDecimalMain {
    public static void main(String... args) {
        BigDecimal a = new BigDecimal("8900");
        BigDecimal b = new BigDecimal("8.9E+3");
        BigDecimal c = new BigDecimal("89E+2");
        BigDecimal d = new BigDecimal("8900.000");

        System.out.println(a.compareTo(b));
        System.out.println(a.compareTo(c));
        System.out.println(a.compareTo(d));
    }
}

输出:

0
0
0

我的程序使用 .equals 匹配对象,但在上述情况下无法给出正确的答案。

问题:如何将字符串统一解析为BigDecimal?我的意思是:

find a function PARSE, that    
for any STR1 && STR2
PARSE(STR1).compareTo(PARSE(STR2)) == 0 <=> PARSE(STR1).equals(PARSE(STR2))

3 个答案:

答案 0 :(得分:2)

使用通用比例,您可以使用setScale(xxx):

    {
        BigDecimal a = new BigDecimal("8900");
        BigDecimal b = new BigDecimal("8.9E+3");
        BigDecimal c = new BigDecimal("89E+2");
        BigDecimal d = new BigDecimal("8900.000");

        System.out.println(a.compareTo(b));
        System.out.println(a.compareTo(c));
        System.out.println(a.compareTo(d));
        System.out.println(a.equals(b));
        System.out.println(a.equals(c));
        System.out.println(a.equals(d));
    }
    {
        BigDecimal a = new BigDecimal("8900").setScale(5);
        BigDecimal b = new BigDecimal("8.9E+3").setScale(5);
        BigDecimal c = new BigDecimal("89E+2").setScale(5);
        BigDecimal d = new BigDecimal("8900.000").setScale(5);

        System.out.println(a.compareTo(b));
        System.out.println(a.compareTo(c));
        System.out.println(a.compareTo(d));
        System.out.println(a.equals(b));
        System.out.println(a.equals(c));
        System.out.println(a.equals(d));
    }

显示

0
0
0
false
false
false
0
0
0
true
true
true

答案 1 :(得分:2)

考虑以下方法:

class UniformDecimal {

    private final BigDecimal decimal;

    public UniformDecimal(BigDecimal decimal) {
        this.decimal = decimal;
    }

    @Override
    public int hashCode() {
        return decimal.toBigInteger().mod(BigInteger.valueOf((1<<31)-1)).intValue();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UniformDecimal that = (UniformDecimal) o;
        return that.decimal.compareTo(this.decimal)==0;
    }
}

虽然,我不确定hashCode的实现

答案 2 :(得分:0)

更新。似乎stripTrailingZeros()做了这件事!

在此处找到有用的内容:HiveDecimal

 private static BigDecimal normalize(BigDecimal bd, boolean allowRounding) {
        if (bd == null) {
            return null;
        }

        bd = trim(bd);

        int intDigits = bd.precision() - bd.scale();

        if (intDigits > MAX_PRECISION) {
            return null;
        }

        int maxScale = Math.min(MAX_SCALE, Math.min(MAX_PRECISION - intDigits, bd.scale()));
        if (bd.scale() > maxScale) {
            if (allowRounding) {
                bd = bd.setScale(maxScale, RoundingMode.HALF_UP);
                // Trimming is again necessary, because rounding may introduce new trailing 0's.
                bd = trim(bd);
            } else {
                bd = null;
            }
        }

        return bd;
    }

    private static BigDecimal trim(BigDecimal d) {
        if (d.compareTo(BigDecimal.ZERO) == 0) {
            // Special case for 0, because java doesn't strip zeros correctly on that number.
            d = BigDecimal.ZERO;
        } else {
            d = d.stripTrailingZeros();
            if (d.scale() < 0) {
                // no negative scale decimals
                d = d.setScale(0);
            }
        }
        return d;
    }