2010-02-05 2 views
11

안녕하세요. 해시 코드 계산에 LINQ의 Enumerable.Sum() 확장 방법을 사용하고 있으며 코드가 커지면 OverflowExceptions에 문제가 있습니다. unchecked 블록에 전화를 걸었지만 도움이되지 않았습니다.Enumerable.Sum() overflowing

방법에 대한 MSDN 문서는 값이 너무 커질 경우가 발생합니다 말한다,하지만 난 반사에 확인하고이 모든이있다 :이 컴파일을 바탕으로

public static int Sum(this IEnumerable<int> source) { 
    if (source == null) { 
     throw Error.ArgumentNull("source"); 
    } 
    int num = 0; 
    foreach (int num2 in source) { 
     num += num2; 
    } 
    return num; 
} 

, 나는 그것을 기대 오버플로 또는 호출 코드의 컨텍스트에 의존하지 않음. 왜 범람하고, 어떻게 멈출 수 있습니까?

+3

이것은 오버플로에 관한 질문에 답하지 않고 있습니다.하지만 '합계'를 사용하여 객체의 해시 코드를 계산한다면 매우 잘 분산 된 해시 코드를 생성하지 못할 것입니다. 일반적인 접근법은 확인되지 않은 상황에서 프라임 곱셈 및 왼쪽 쉬프트와 같은 것입니다. –

+0

그래, 이상적은 아니지만 합계 해시 코드 (하위 구성 요소의 해시 코드)가 훨씬 더 나은 방식으로 생성되므로 걱정하지 않아도됩니다. (나는 단지 'int'를 추가하는 것이 아니라, 작은 변화가 매우 다른 코드를 생성하지는 않는다.) 나는 이것이 내가 미쳐야 할 것이 아니라고 생각하지만, 아마 그것이 상상하는 것보다 더 중요 할 것이다 ...? –

+0

해시 코드가 Int32.MaxValue 또는 그 근처에있는 경우 두 항목으로 오버플로 할 수 있습니다. int를 다루기 때문에 아이템을 많이 가질 때까지는 명확하지 않지만, 적절히 분산 된 해시 함수를 사용하면 예외를 던질 때가 많습니다. – thecoop

답변

9

코드는 실제로 C# checked 블록에서 실행됩니다. 문제는 반사경이 블록 checked을 적절하게 디 컴파일하지 않고 정상적인 수학 연산으로 표시한다는 것입니다. 체크 된 블록을 생성하고, 코드를 컴파일 한 다음 리플렉터에서 디 컴파일하여이를 직접 확인할 수 있습니다.

디 컴파일 된 C# 코드 대신 IL을 보면이 사실을 확인할 수도 있습니다. add IL opcode 대신에 add.ovf가 추가 된 것을 볼 수 있습니다. 이 오버 플로우에 던지지이 특정 방법을 얻을 수있는 방법은 없습니다 오버 플로우

L_001a: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() 
L_001f: stloc.1 
L_0020: ldloc.0 
L_0021: ldloc.1 
L_0022: add.ovf <-- This is an overflow aware addition 
L_0023: stloc.0 
L_0024: ldloc.2 

에 던져 추가의 버전입니다. 가장 좋은 옵션은 다음

  1. 같은 long
  2. 이 외에도에게
+0

감사합니다. 일리노이에 더 익숙해 져야합니다 ... –

1

checked를 확인 사용하지 않는 합계의 자신의 버전을 쓰기 더 큰 유형으로 전환은 현재 블록의 표현에 적용됩니다 (이미 컴파일 된) 메소드가 아닙니다. 검사되지 않은 수학을 사용하려면 unchecked 블록 내에 Sum의 자체 버전을 구현해야합니다.

+0

그래서 체크/체크되지 않은 구별이 결정됩니다 컴파일 시간에? 나는 그것이 컨텍스트에 따라 런타임이 될 것이라고 예상했지만, 내가 틀릴 것이라고 생각한다. –

+0

JaredPar가 대답 했으므로 JaredPar는 확인되었거나 확인되지 않은 블록인지 여부에 관계없이 다른 IL 명령을 생성합니다. 너는 이미 컴파일 된 IL을 변경할 수 없다. – thecoop

7

이 함수는 제네릭 enumerables에 대해 작성했습니다. 나는 그것에 대해 어떤 말도 듣고 싶다.

public static int SequenceHashCode<T>(IEnumerable<T> seq) 
{ 
    unchecked 
    { 
     return seq != null ? seq.Aggregate(0, (sum,obj) => sum+obj.GetHashCode()) : 0; 
    } 
} 
+1

나는 그것을 좋아한다. 멀리 볼 수있는 obj에 대한 검사 == null이 없습니다. – Fried