2013-01-14 1 views
9

Jackson (버전 2.1.x)에 의존하는 Java로 작성된 JSON 스키마 구현이 있습니다. 정확성을 이유로 Jackson에게 부동 소수점 숫자에 BigDecimal을 사용하라고 지시합니다."정규화"BigDecimal의 해시 코드 : howto?

JSON 스키마의 필요성에 대한 특별한 요구가 있습니다. JSON 값의 동일성은 숫자 값에 대해 수학적 값의 동일성으로 정의됩니다.

{ "enum": [ 1, 1.0 ] } 

그러나 JsonNodes 11.0에 대한 동일하지 : 예를 들어,이 법적 스키마 (AN enum의 값은 고유해야합니다) 아니다, 이후 체크 이런 종류의 필요합니다. 따라서 Guava의 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의 전체 코드)의 BigDecimal compareTo와 순서에 더블 더블의 해시 코드를 사용하는

+0

@zsxwing : doEquivalent가 이미 오버라이드되었습니다. 편집을 참조하십시오. 전체 구현에 대한 링크를 추가했습니다. – fge

+2

명확하지 않습니다. 코드가 동일한 값에 대해 동일한 해시 코드를 반환하지 않는 문제가 있습니까? 실수로 모든 고유 값에 대해 고유 한 해시 코드를 보장하려고합니까? –

+0

"1", "1.0", "1.00"이 동일한 해시 코드를 반환하겠습니까? 어쩌면 hashCode를 사용하지 않는 TreeSet을 사용할 수 있습니까? – zsxwing

답변

12

변환하지만, 기본 평등.

수치 적으로 동일한 BigDecimal 두 개가 동일한 Double에 매핑되고 동일한 hashCode를 얻습니다. 매우 약간 다른 BigDecimal 값은 이중 반올림으로 인해 동일한 해시 코드를 갖지만 대부분의 고유 값은 필요한 모든 해시 코드를 갖게됩니다.

+1

저는 .compareTo()를 평등하게 사용합니다. 그건 내가 생각하지 못했던 간단한 해결책이다. – fge

+0

매우 큰 값에 대해 반환되는 double 값은 정확하지 않은 이유로 처리 할 수 ​​없다는 점이 궁금한가요? – fge

+1

Double.MAX_VALUE보다 큰 모든 숫자는 무한대에 매핑되어 동일한 해시 코드를 가져옵니다. 마찬가지로, 매우 작은 수는 0으로 매핑되고 동일한 해시 코드를 얻습니다. 그렇지 않으면 16 자리의 최상위 숫자와 일치하는 고유 한 숫자 쌍이 동일한 해시 코드를 갖게됩니다. –