2013-01-14 30 views
9

Java'da yazılmış bir JSON Şema uygulaması var, bu da Jackson (sürüm 2.1.x). Kesinlik nedeniyle, Jackson'a kayan noktalı sayılar için BigDecimal kullanmasını söylüyorum.BigDecimal hash kodu "Normalleştiriliyor": Howto?

JSON Şeması'nın gereksinimleri için, belirli bir gereksinim vardır: JSON değeri eşitliği, sayısal değerler için, matematik değerlerinin eşitliği ile tanımlanır.

{ "enum": [ 1, 1.0 ] } 

Ama JsonNodes 1 ve 1.0 için eşit değildir: Örneğin, bu yasal bir şema (bir enum değerler benzersiz olmalıdır) değil, çünkü ben çek bu tür gerekiyor. Bu nedenle, Guava'nın Equivalence bir uygulamasını kodluyorum ve uygun olduğunda Set<Equivalence.Wrapper<JsonNode>> kullanın. Ve bu uygulama sadece sayısal düğümler değil, tüm düğüm türleri için çalışmalıdır.

Ve bu uygulamanın en zor kısmı sayısal düğümler için doHash() olarak çıkıyor:/onlar tamsayı veya kayan noktalı sayılar olsun, eşdeğer matematiksel değerler için aynı karma kodunun gerekir.

@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 

Bu anda, olup, en iyi ben ile gelebilir:

şu anda birlikte gelen en iyi budur.

Böyle bir hashcode hesaplamak için daha iyi bir yolu var mı?

(düzenleme: Denklik uygulanması here tam kodu) BigDecimal compareTo sipariş üzerine katlayın ve Çift Kişilik en hashCode kullanmak

+0

@zsxwing: doEquivalent zaten geçersizdir - bkz. Düzenle, Uygulamanın tamamına bir bağlantı ekledim – fge

+2

Net değil - kodun eşit değerler için eşit karma kodları döndürmediği bir sorun var mı, yoksa yanlışlıkla) her bir farklı değer için benzersiz bir karma kodu sağlamaya çalışıyor musunuz? –

+0

Bunu "1", "1.0", "1.00" aynı karma kodu geri döndürmek ister misiniz? Belki hashCode kullanmayan TreeSet'i kullanabilirsiniz? – zsxwing

cevap

12

dönüştürme, ancak baz eşitlik.

Sayısal olarak eşdeğer BigDecimals, aynı Double'e eşlenecek ve aynı hashCode değerini alacaktır. Çok az farklı olan bazı BigDecimal değerler, çift yuvarlama nedeniyle aynı hashcode değerini alır, ancak en belirgin değerler, ihtiyacınız olan tüm farklı kodları alır.

+1

için BigDecimal'i kullanmasını istemem için tam olarak eşitlik için '.compareTo()' kullanıyorum. Bu kadar basit bir çözüm bulamadım ... – fge

+0

Çok büyük değerler için hangi çifte değerlerin döndüğüne dair bir merak var; – fge

+1

Double.MAX_VALUE değerinden daha büyük olan tüm sayılar sonsuza eşlenecek ve aynı hashcode değerini alacaktır. Benzer şekilde, çok küçük sayılar sıfıra eşlenecek ve aynı hash kodunu alacaktır. Aksi takdirde, en önemli 16 hane ile eşleşen ayrı sayıdaki çiftler aynı karma kodu alırlar. –