"规范化"BigDecimal的哈希码:howto?

fge*_*fge 13 java hashcode bigdecimal guava

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

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

{ "enum": [ 1, 1.0 ] }
Run Code Online (Sandbox Code Playgroud)

但对于JsonNodes 11.0不相等.因此,我编写了番石榴等效的实现,并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
Run Code Online (Sandbox Code Playgroud)

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

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

(编辑:此处等效实现的完整代码)

Pat*_*han 18

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

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

  • 所有大于 Double.MAX_VALUE 的数字都将映射到无穷大,并获得相同的哈希码。同样,非常小的数字将映射为零,并获得相同的哈希码。否则,匹配大约 16 个最高有效数字的不同数字对将获得相同的哈希码。 (3认同)

Víc*_*Gil 5

使用BigDecimal::stripTrailingZeros()方法,它BigDecimalBigDecimal表示相同数学数字的两个不同对象返回相同的对象,即它们具有不同数量的无意义数字,例如3.50(小数位数为二)和3.5(小数位数为一):

return decimal.stripTrailingZeros().hashCode();
Run Code Online (Sandbox Code Playgroud)