2017-05-07 1 views
2

있습니다. 이 같은 입력 데이터가있는 경우는 :같은 구조체 내가 코드가 서로 다른 해시 코드

-0,25 
0 
1 
-450335288 
--------------- 
-0,25 
0 
1 
-450335288 
--------------- 
-0,25 
0 
1 
-450335288 
--------------- 

하지만 인수를 변경하는 경우 :

prg.MaxPoints(new Point[] { new Point(4, -1), new Point(4, 0), new Point(4, 5) }); 

디버그 출력된다. 주문 :

prg.MaxPoints(new Point[] { new Point(4, 0),new Point(4, -1) , new Point(4, 5) }); 

디버그 밖으로 :

-0,25 
0 
1 
1697148360 
--------------- 
-0,25 
0 
1 
-450335288 
--------------- 
-0,25 
0 
1 
-450335288 
--------------- 

그리고 중요 할 수 한 가지가 첫 번째 경우에 우리는 (GetFromPoints 방법) 긍정적 모든 "디바이더"을 가지고입니다 (4 , 24,20) 두 번째 경우에는 그 중 하나가 음수이고 다른 두 개가 양수이면 (-4,20,24)입니다. 아무도 이것에 대해 설명 할 수 있습니까?

UPD. i는 음으로 나누어 0 0이 아니라는 것을 의미한다

return new Coefficients(a/divider, 0, c/divider);//anyway in all of these cases 2-nd argument is 0 

return new Coefficients(a/divider, b/divider, c/divider); 

변경된 경우?

+0

네,하지만 같은 필드가있는 구조체가 서로간에 같아야한다고 생각했지만 그렇지 않습니다. 'Debug.WriteLine (coef_list [0] .a.Equals (coef_list [1] .a)); Debug.WriteLine (coef_list [0] .b.Equals (coef_list [1] .b)); Debug.WriteLine (coef_list [0] .c.Equals (coef_list [1] .c)); 의 Debug.WriteLine (coef_list [0] .Equals (coef_list [1]));' 표시 '사실 그들은 동일하지 FALSE ' –

+0

가, 수학이 당신에게 반올림 오류를 제공 사실 사실, 그래서'- 0,25'는 그렇지 않습니다. a, b, c 값을 출력 할 때'.ToString ("G17")' –

+0

바이트를 엿보는 것은 어쩌면 언더 플로우가있는 것 같아요. 바이트이지만 개념적으로 동일한 값을 제공합니다. 첫 번째 경우, 첫 번째 구성 요소는 정확하게 '0 0000000000000000' 인'b '를 가지며 두 번째 경우에는'0 0000000000000080'과 약간 다릅니다. –

답변

2

기본적으로 음수 0 값이 두 배가됩니다. 그러나 구조체의 런타임 기본 GetHashCode는 맹목적으로 기본 바이트를 결합하고 필드의 GetHashCode를 호출하지 않습니다.

public struct S 
{ 
    public double value; 

    public S(double d) 
    { 
     value = d; 
    } 
} 

public static void Main(string[] args) 
{   
    double d1 = 0; 
    double d2 = d1/-1; 

    Console.WriteLine("using double"); 
    Console.WriteLine("{0} {1}", d1, d1.GetHashCode()); 
    Console.WriteLine(GetComponentParts(d1)); 
    Console.WriteLine("{0} {1}", d2, d2.GetHashCode()); 
    Console.WriteLine(GetComponentParts(d2)); 
    Console.WriteLine("Equals: {0}, Hashcode:{1}, {2}", d1.Equals(d2), d1.GetHashCode(), d2.GetHashCode()); 

    Console.WriteLine(); 
    Console.WriteLine("using a custom struct"); 

    var s1 = new S(d1); 
    var s2 = new S(d2); 
    Console.WriteLine(s1.Equals(s2)); 
    Console.WriteLine(new S(d1).GetHashCode()); 
    Console.WriteLine(new S(d2).GetHashCode());    
} 

// from: https://msdn.microsoft.com/en-us/library/system.double.epsilon(v=vs.110).aspx 
private static string GetComponentParts(double value) 
{ 
    string result = String.Format("{0:R}: ", value); 
    int indent = result.Length; 

    // Convert the double to an 8-byte array. 
    byte[] bytes = BitConverter.GetBytes(value); 
    // Get the sign bit (byte 7, bit 7). 
    result += String.Format("Sign: {0}\n", 
          (bytes[7] & 0x80) == 0x80 ? "1 (-)" : "0 (+)"); 

    // Get the exponent (byte 6 bits 4-7 to byte 7, bits 0-6) 
    int exponent = (bytes[7] & 0x07F) << 4; 
    exponent = exponent | ((bytes[6] & 0xF0) >> 4); 
    int adjustment = exponent != 0 ? 1023 : 1022; 
    result += String.Format("{0}Exponent: 0x{1:X4} ({1})\n", new String(' ', indent), exponent - adjustment); 

    // Get the significand (bits 0-51) 
    long significand = ((bytes[6] & 0x0F) << 48); 
    significand = significand | ((long) bytes[5] << 40); 
    significand = significand | ((long) bytes[4] << 32); 
    significand = significand | ((long) bytes[3] << 24); 
    significand = significand | ((long) bytes[2] << 16); 
    significand = significand | ((long) bytes[1] << 8); 
    significand = significand | bytes[0];  
    result += String.Format("{0}Mantissa: 0x{1:X13}\n", new String(' ', indent), significand);  

    return result; 
} 

출력 : 로그인 : : 0 (+)
지수 :

더블
0 0
0 사용 0xFFFFFC02을 (-1022 여기에 당신이 무엇을보고의 단순화 된 버전입니다)
가수 : 0x0000000000000

0 0
0 : 로그인 : 1 (-) 012,380, 지수 : 0xFFFFFC02 (-1022)
가수 : 0x0000000000000

가 같음 : 사실, 해시 코드 (Hashcode) : 0, 0


거짓 사용자 정의 구조체를 사용하여
346,948,956
-1800534692

나는 두 개의 이중 중 하나를 "정상"제로로 정의하고 다른 하나는 "음수"제로로 정의했습니다. 이 둘의 차이점은 double의 부호 비트에 있습니다. 두 값은 바이트 수준을 제외하고 모든 명백한 방식 (Equals 비교, GetHashCode, ToString 표현)에서 동일합니다.그러나 사용자 지정 구조체에 넣을 때 런타임의 GetHashCode 메서드는 동일한 값을 포함하는 각 구조체마다 다른 해시 코드를 제공하는 원시 비트를 결합합니다. 같음은 똑같은 일을하고 거짓 결과를 얻습니다.

나는 이것이 일종의 큰 잡았다는 것을 인정한다. 이에 대한 해결책은 Equals와 GetHashCode를 재정 의하여 원하는 적절한 평등을 얻는 것입니다.

실제로 비슷한 문제가 언급되었습니다. before 분명히 런타임은 구조체의 필드가 모두 8 바이트 크기 일 때만 수행합니다.

+0

고맙습니다. 훌륭한 수사. –

관련 문제