18

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

对于 JSON Schema 的需求,有一个特殊的需求:JSON 值相等,对于数值,是通过它们的数学值相等来定义的。我需要这种检查,例如,这不是一个合法的模式(an 中的值enum应该是唯一的):

{ "enum": [ 1, 1.0 ] }

但是 JsonNodes for 1and1.0是不相等的。因此,我编写了 Guava's 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

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

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

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

4

2 回答 2

23

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

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

于 2013-01-14T04:19:54.013 回答
7

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

return decimal.stripTrailingZeros().hashCode();
于 2021-01-10T20:43:47.920 回答