У меня есть большой словарь, в котором ключ десятичный, но 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.
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")));
Если вы просто пытаетесь получить другой алгоритм хеширования, нет необходимости преобразовывать его в 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
, передающий соответствующие значения из массива.
Я несколько подозреваю, что десятичный
хэш-код настолько плох. У вас есть образец кода для этого?
Распределение GUID хорошо, поскольку оно должно быть уникальным...
Какой диапазон чисел используется для этого? Реализация GetHashcode()
по умолчанию для Decimal
может учитывать только определенный диапазон значений.
Преобразуйте десятичное значение в массив байтов, а затем создайте из него 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));