2016-12-01 6 views
4

아래와 같이 MS-SQL 데이터베이스에 값을 저장하기 위해 ulong을 long (그리고 그 반대) 및 int (또는 그 반대로)에 매핑하려고합니다. 부호있는 정수 정수 및 정수 정수입니다.C#에서 long으로 ulong을 매핑 하시겠습니까?

숫자 (uint, ulong)가 uint/ulong 범위 (IP -v4 & v6, 실제로는 ulong이 실제로 존재 함)의 범위 내인지 여부를 (데이터베이스에서) 확인해야하기 때문에이 작업을 수행합니다. 두 개의 ulong으로 구성된 uint128).

UlongToLong

UIntToInt

다음 코드를 이러한 목표를 달성하기 위해보다 효율적인 방법이 있나요 내가 여기있다 :

public static ulong SignedLongToUnsignedLong(long signedLongValue) 
{ 
    ulong backConverted = 0; 

    // map ulong to long [ 9223372036854775808 = abs(long.MinValue) ] 
    if (signedLongValue < 0) 
    { 
     // Cannot take abs from MinValue 
     backConverted = (ulong)System.Math.Abs(signedLongValue - 1); 
     backConverted = 9223372036854775808 - backConverted - 1; 
    } 
    else 
    { 
     backConverted = (ulong)signedLongValue; 
     backConverted += 9223372036854775808; 
    } 

    return backConverted; 
} 


public static long UnsignedLongToSignedLong(ulong unsignedLongValue) 
{ 
    // map ulong to long [ 9223372036854775808 = abs(long.MinValue) ] 
    return (long) (unsignedLongValue - 9223372036854775808); 
} 


public static int UnsignedIntToSignedInt(uint unsignedIntValue) 
{ 
    // map uint to int [ 2147483648 = abs(long.MinValue) ] 
    return (int)(unsignedIntValue - 2147483648); 
} 


public static uint SignedIntToUnsignedInt(int signedIntValue) 
{ 
    uint backConverted = 0; 

    // map ulong to long [ 2147483648 = abs(long.MinValue) ] 
    if (signedIntValue < 0) 
    { 
     // Cannot take abs from MinValue 
     backConverted = (uint)System.Math.Abs(signedIntValue - 1); 
     backConverted = 2147483648 - backConverted - 1; 
    } 
    else 
    { 
     backConverted = (uint)signedIntValue; 
     backConverted += 2147483648; 
    } 

    return backConverted; 
} 


public static void TestLong() 
{ 
    long min_long = -9223372036854775808; 
    long max_long = 9223372036854775807; 

    ulong min_ulong = ulong.MinValue; // 0 
    ulong max_ulong = ulong.MaxValue; // 18446744073709551615 = (2^64)-1 

    long dbValueMin = UnsignedLongToSignedLong(min_ulong); 
    long dbValueMax = UnsignedLongToSignedLong(max_ulong); 


    ulong valueFromDbMin = SignedLongToUnsignedLong(dbValueMin); 
    ulong valueFromDbMax = SignedLongToUnsignedLong(dbValueMax); 

    System.Console.WriteLine(dbValueMin); 
    System.Console.WriteLine(dbValueMax); 

    System.Console.WriteLine(valueFromDbMin); 
    System.Console.WriteLine(valueFromDbMax); 
} 


public static void TestInt() 
{ 
    int min_int = -2147483648; // int.MinValue 
    int max_int = 2147483647; // int.MaxValue 

    uint min_uint= uint.MinValue; // 0 
    uint max_uint = uint.MaxValue; // 4294967295 = (2^32)-1 


    int dbValueMin = UnsignedIntToSignedInt(min_uint); 
    int dbValueMax = UnsignedIntToSignedInt(max_uint); 

    uint valueFromDbMin = SignedIntToUnsignedInt(dbValueMin); 
    uint valueFromDbMax = SignedIntToUnsignedInt(dbValueMax); 

    System.Console.WriteLine(dbValueMin); 
    System.Console.WriteLine(dbValueMax); 

    System.Console.WriteLine(valueFromDbMin); 
    System.Console.WriteLine(valueFromDbMax); 
} 
+0

안녕하세요! http://codereview.stackexchange.com/에서이 질문을하는 것이 좋습니다. 성능을 향상시키기위한 피어 리뷰 코드는 그들이 성능이 뛰어나다 고 생각하는 것 중 하나입니다. –

+0

당신은 http://stackoverflow.com/a/21854586/1383168에서 분기 예측 오류를 피할 수 있습니다. – Slai

답변

4

ulong에서 long에 매핑, 출연진과 long.MinValue을 추가하려면. long에서 ulong으로 다시 매핑하려면 long.MinValue을 빼고 캐스팅하십시오. 두 경우 모두, 검사되지 않은 컨텍스트를 사용하여 오버 플로우 조건이 무시되도록하십시오. uintint에 대한

public static long MapUlongToLong(ulong ulongValue) 
{ 
    return unchecked((long)ulongValue + long.MinValue); 
} 

public static ulong MapLongToUlong(long longValue) 
{ 
    return unchecked((ulong)(longValue - long.MinValue)); 
} 

논리 정확히 유사하다.

+0

이것이 맞지만. 긴 메모리 필드의 복사본을 여전히 필요로하기 때문에 "상대적으로"느립니다 ... 나는 멋진 방법을 선호합니다. – Aron

+0

IMHO,'+ long.MinValue' 및'- long.MinValue'를'^ long.MinValue'로 바꿀 수 있습니다. – PetSerAl

+0

@Aron 두 가지 방법 모두 인자를로드하고, 즉시로드하고, 더하거나 빼거나, 반환하는 네 가지 명령어로 컴파일합니다. 이러한 메소드 호출 중 하나가 인라인되면 가장 좋은 경우에는 두 가지 지침 만됩니다. 두 개 미만의 명령어를 사용하는 솔루션이 있습니까? –

0

비록 Tanner Swett가 정확합니다. 훨씬 더 좋고 더러운 해결책은 ulong에 대한 액세스를 long과 동일한 메모리 주소에 매핑하도록 .net에 알리는 것입니다. 이렇게하면 즉각적인 전환 속도를 얻을 수 있습니다.

void Main() 
{ 
    var foo = new Foo { Long = -1 }; 

    Console.WriteLine(foo.ULong); 
} 

// Define other methods and classes here 
[StructLayout(LayoutKind.Explicit)] 
public class Foo 
{ 
    [FieldOffset(0)] 
    private ulong _ulong; 

    [FieldOffset(0)] 
    private long _long; 

    public long Long 
    { 
     get { return _long; } 
     set { _long = value; } 
    } 

    public ulong ULong 
    { 
     get { return _ulong; } 
     set { _ulong = value; } 
    } 
} 

표시된 속성을 사용하도록 엔티티 프레임 워크 POCO를 설정하면 필드가 매핑되는 메모리 주소를 제어 할 수 있습니다.

따라서 변환이 발생하지 않습니다.

이 코드는 Tanner Swett보다 100 % 빠릅니다.

+1

그러나 코드는 OP가 원하는대로 값을 매핑하지 않습니다. 또한 AFAIK, 겹쳐진 필드는 코드가 완전 신뢰 권한으로로드되어야했습니다. – PetSerAl

+1

내 코드가 시간을 변환하는 데 사용할 수있는 소스를 제공 할 수 있습니까?CPU가 부호있는 값과 부호없는 값을 다르게 저장하지 않기 때문에'(long)'과'(ulong)'캐스트가 기계어로 컴파일되면 아무 것도되지 않을 것으로 예상됩니다. –

+0

@TannerSwett에 동의하십시오. 'long'에서 'ulong'으로의 변환은 MSIL에서 본질적으로 no-op입니다. – PetSerAl