Преобразование System.Decimal в System.Guid

У меня есть большой словарь, в котором ключ десятичный, но GetHashCode () System.Decimal катастрофически плох. Чтобы доказать свою догадку, я запустил цикл for с 100.000 соседних десятичных знаков и проверил распределение. 100 000 различных десятичных чисел использовали только 2 (два !!!) различных хеш-кода.

Десятичное число представлено в виде 16 байтов. Так же, как Guid! Но GetHashCode () дистрибутива Guid довольно хорош. Как я могу преобразовать десятичную в Guid в C # как можно дешевле? Я запустил цикл for с 100.000 соседних десятичных знаков и проверил распределение. 100 000 различных десятичных чисел использовали только 2 (два !!!) различных хеш-кода.

Десятичное число представлено в виде 16 байтов. Так же, как Guid! Но GetHashCode () дистрибутива Guid довольно хорош. Как я могу преобразовать десятичную в Guid в C # как можно дешевле? Я запустил цикл for с 100.000 соседних десятичных знаков и проверил распределение. 100 000 различных десятичных чисел использовали только 2 (два !!!) различных хеш-кода.

Десятичное число представлено в виде 16 байтов. Так же, как Guid! Но GetHashCode () дистрибутива Guid довольно хорош. Как я могу преобразовать десятичную в Guid в C # как можно дешевле? Небезопасный код в порядке!


РЕДАКТИРОВАТЬ: Тест был запрошен, поэтому вот код:

decimal d = 96000000000000000000m;
Dictionary<int, int> hashcount = new Dictionary<int, int>();
int length = 100000;
for (int i = 0; i < length; i++)
{
    int hashcode = d.GetHashCode();
    int n;
    if (hashcount.TryGetValue(hashcode, out n))
    {
        hashcount[hashcode] = n + 1;
    }
    else
    {
        hashcount.Add(hashcode, 1);
    }
    d++;
}

Console.WriteLine(hashcount.Count);

Это печатает 7. Я не помню начального десятичного числа, которое дало мне 2.

10
задан Hooked 6 March 2015 в 05:01
поделиться

4 ответа

ЧРЕЗВЫЧАЙНО ХАРАКТЕРНОЕ РЕШЕНИЕ (но, вероятно, самое быстрое из возможных)

public static class Utils
{
    [StructLayout(LayoutKind.Explicit)]
    struct DecimalGuidConverter
    {
        [FieldOffset(0)]
        public decimal Decimal;
        [FieldOffset(0)]
        public Guid Guid;
    }

    private static DecimalGuidConverter _converter;
    public static Guid DecimalToGuid(decimal dec)
    {
        _converter.Decimal = dec;
        return _converter.Guid;
    }
    public static decimal GuidToDecimal(Guid guid)
    {
        _converter.Guid = guid;
        return _converter.Decimal;
    }
}

// Prints 000e0000-0000-0000-8324-6ae7b91d0100
Console.WriteLine(Utils.DecimalToGuid((decimal) Math.PI));

// Prints 00000000-0000-0000-1821-000000000000
Console.WriteLine(Utils.DecimalToGuid(8472m));

// Prints 8472
Console.WriteLine(Utils.GuidToDecimal(Guid.Parse("00000000-0000-0000-1821-000000000000")));
23
ответ дан 3 December 2019 в 15:34
поделиться

Если вы просто пытаетесь получить другой алгоритм хеширования, нет необходимости преобразовывать его в Guid. Примерно так:

public int GetDecimalHashCode(decimal value)
{
    int[] bits = decimal.GetBits(value);
    int hash = 17;
    foreach (int x in bits)
    {
        hash = hash * 31 + x;
    }
    return hash;
}

(Очевидно, замените другой алгоритм, если хотите.)

По общему признанию, это все еще связано с созданием массива, что не идеально. Если вы действительно хотите создать Guid, вы можете использовать приведенный выше код для получения битов, а затем длинный конструктор Guid , передающий соответствующие значения из массива.

Я несколько подозреваю, что десятичный хэш-код настолько плох. У вас есть образец кода для этого?

5
ответ дан 3 December 2019 в 15:34
поделиться

Распределение GUID хорошо, поскольку оно должно быть уникальным...

Какой диапазон чисел используется для этого? Реализация GetHashcode() по умолчанию для Decimal может учитывать только определенный диапазон значений.

0
ответ дан 3 December 2019 в 15:34
поделиться

Преобразуйте десятичное значение в массив байтов, а затем создайте из него GUID:

public static byte[] DecimalToByteArray (decimal src) 
{
    using (MemoryStream stream = new MemoryStream()) 
    {
        using (BinaryWriter writer = new BinaryWriter(stream))
        {
            writer.Write(src);
            return stream.ToArray();
        }
    }
}

Decimal myDecimal = 1234.5678M;
Guid guid = new Guid(DecimalToByteArray(myDecimal));
0
ответ дан 3 December 2019 в 15:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: