2016-12-01 4 views
4

MS-SQLデータベースに値を保存するために、以下に示すように、ulongをlong(およびその逆)に、uintをint(またはその逆)にマップしようとしています。整数型と整数型のみです。C#でlong型にulongをマッピングしていますか?

uint/ulongの範囲(IP-v4 & v6;実際にはulongが現実にある)の範囲内の数値(uint、ulong)が範囲内にあるかどうかをチェックする必要があるため2つの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/でこの質問をすることをお勧めします。パフォーマンスを向上させるためのピアレビューコードは、彼らが優れていることの1つです。 –

+0

あなたはブランチ予測を避けるためにhttp://stackoverflow.com/a/21854586/1383168をチェックすることができます – Slai

答えて

4

ulongからlongにマップ、キャストとlong.MinValueを追加します。 longからulongにマップするには、long.MinValueを引いてキャストします。いずれの場合も、チェックされていないコンテキストを使用してオーバーフロー条件が無視されるようにします。

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

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

uintintためのロジックは、正確に類似しています。

+0

これは間違いありません。長いメモリフィールドのコピーをまだ必要としているので、「比較的」遅いです...私はすばらしいためにblittedアプローチを好むでしょう。 – Aron

+0

IMHOでは、 '+ long.MinValue'と' - long.MinValue'を '^ long.MinValue'に置き換えることができます。 – PetSerAl

+0

@Aron私の両方の方法は、引数をロードし、即時にロードし、加算または減算して戻ります。これらのメソッド呼び出しの1つがインライン展開されている場合、最適なケースでは2つの命令になります。 2つ以下の命令を使用するソリューションがありますか? –

0

しかし、Tanner Swettは正しいです。はるかに良いと汚れた解決策はulongのためのアクセスをlongと同じメモリアドレスにマップすることです。これにより、瞬間的な変換速度が得られます。

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'sより100%高速です。

+1

しかしあなたのコードは、OPが望むように値をマップしません。また、AFAIKでは、オーバーラップしたフィールドでコードに完全な信頼特権がロードされている必要がありました。 – PetSerAl

+1

私のコードが時間を費やすという事実のために何らかのソースを提供できますか?CPUは符号付きと符号なしの値を別々に格納しないので、 '(long)'と '(ulong)'キャストは、マシンコードにコンパイルされても何も変わらないものと思われます。 –

+0

@TannerSwettに同意すると、チェックされていない「long」から「ulong」への変換は、本質的にMSILではノーオペレーションではありません。 – PetSerAl

関連する問題