“规范化”BigDecimal哈希码:如何?

时间:2013-01-14 02:33:23

标签: java guava hashcode bigdecimal

我有一个用Java编写的JSON Schema实现,它依赖于Jackson(版本2.1.x)。出于准确性原因,我告诉Jackson使用BigDecimal作为浮点数。

对于JSON Schema的需求,特别需要:对于数值,JSON值相等由其数学值的相等性定义。我需要这种检查,例如,这不是一个合法的模式(enum中的值应该是唯一的):

{ "enum": [ 1, 1.0 ] }

11.0的JsonNodes不相等。因此,我编写了番石榴Equivalence的实现,并在适当的地方使用Set<Equivalence.Wrapper<JsonNode>>。此实现应该适用于所有类型的节点,而不仅仅是数字节点。

对于数字节点,此实现中最困难的部分是doHash():/我需要相同的哈希码以获得等效的数学值,无论它们是整数还是浮点数

目前我能想出的最好的是:

@Override
protected int doHash(final JsonNode t)
{
    /*
     * If this is a numeric node, we want a unique hashcode for all possible
     * number nodes.
     */
    if (t.isNumber()) {
        final BigDecimal decimal = t.decimalValue();
        try {
            return decimal.toBigIntegerExact().hashCode();
        } catch (ArithmeticException ignored) {
            return decimal.stripTrailingZeros().hashCode();
        }
    }

    // etc etc -- the rest works fine

目前,这是我能想到的最好的。

有没有更好的方法来计算这样的哈希码?

编辑:等效实现的完整代码here

2 个答案:

答案 0 :(得分:18)

转换为Double并使用Double的hashCode,但BigDecimal compareTo顺序的基本相等。

两个数字等效的BigDecimals将映射到同一个Double,并获得相同的hashCode。由于双舍入,一些稍微不同的BigDecimal值将获得相同的哈希码,但是大多数不同的值将获得不同的哈希码,这就是您所需要的。

答案 1 :(得分:3)

使用 BigDecimal::stripTrailingZeros() 方法,它为两个不同的 BigDecimal 对象返回相同的 BigDecimal 对象,它们代表相同的数学数字,即它们具有不同数量的无意义数字,对于示例 3.50(比例为 2)和 3.5(比例为 1):

return decimal.stripTrailingZeros().hashCode();