2016-12-01 6 views
4

Я пытаюсь отобразить ulong на длинный (и наоборот) и uint на int (и наоборот), как показано ниже, - чтобы сохранить значения в базе данных MS-SQL с помощью подписанные типы integer и biginteger.Сопоставление улонга с длинным в C#?

Я делаю это, потому что я должен проверить (в базе данных), находится ли число (uint, ulong) в пределах диапазона в наборе диапазонов uint/ulong (IPs - v4 & v6; на самом деле улунг в действительности 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 и бросить. В любом случае используйте непроверенный контекст, чтобы условия переполнения игнорировались.

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

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

Логика uint и int совершенно аналогично.

+0

Хотя это верно. Это «относительно» медленно, так как вам все еще нужно сделать копию длинного поля памяти ... Я бы предпочел, чтобы блистательный подход был потрясающим. – Aron

+0

ИМХО, вы можете заменить '+ long.MinValue' и' - long.MinValue' на '^ long.MinValue'. – PetSerAl

+0

@Aron Оба моих метода составляют всего четыре инструкции: загрузить аргумент, загрузить сразу, добавить или вычесть, вернуть. Если один из этих вызовов метода встроен, это будет всего лишь двумя инструкциями в лучшем случае. У вас есть решение, которое использует менее двух инструкций? –

0

Несмотря на то, что Tanner Swett является правильным. Гораздо приятнее и грязнее, чтобы сказать .net, чтобы сопоставить доступ для 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; } 
    } 
} 

Устанавливая ваши рамки сущности ПОКО использовать атрибуты показано, вы можете контролировать память адрес, поля сопоставляются.

Следовательно, никакого преобразования никогда не происходит.

Этот код на 100% быстрее, чем у Tanner Swett's.

+1

Но ваш код не отображает значения, как требуется OP. Кроме того, поля AFAIK, перекрывающиеся, требовали, чтобы ваш код был загружен с полными правами доверия. – PetSerAl

+1

Можете ли вы предоставить какой-то источник факта, что мой код будет тратить время на преобразование?Поскольку ЦП не сохраняет значения подписи и без знака по-разному, я бы ожидал, что мои '(long)' и '(ulong)' casts превратятся в ничто, когда они будут скомпилированы в машинный код. –

+0

Согласитесь с @TannerSwett, неконтролируемое преобразование 'long' в' ulong' практически не работает в MSIL. – PetSerAl