Преобразовательная Система.Десятичной системы.идентификатор GUID
У меня есть большой словарь, где ключ десятичный, но GetHashCode () системы.Десятичный является disasterously плохо. Чтобы доказать свою догадку, я запустил цикл for со 100.000 соседними десятичными знаками и проверил распределение. 100.000 различных десятичных чисел используется только 2 (два!!!) различные хэш-коды.
Decimal представлен в виде 16 байт. Как и Guid! Но распределение Guid GetHashCode () довольно хорошее. как я могу преобразовать decimal в Guid в C# так же дешево, как возможно? Небезопасный код в порядке!
EDIT: тест был запрошен, поэтому вот код:
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.
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")));
Если вы просто пытаетесь получить другой алгоритм хэша, нет необходимости конвертировать в Guid. Что-то вроде этого:--4-->
public int GetDecimalHashCode(decimal value)
{
int[] bits = decimal.GetBits(value);
int hash = 17;
foreach (int x in bits)
{
hash = hash * 31 + x;
}
return hash;
}
(очевидно, замените другой алгоритм, если хотите.)
По общему признанию, это все еще включает в себя создание массива, который не идеален. Если ты ... --8-->действительно хотите создать Guid вы можете использовать код выше, чтобы получить биты, а затем долго Guid
конструктор передача соответствующих значений из матрица.
Я несколько подозрительно отношусь к decimal
hashcode так плохо, хотя. У вас есть образец кода для этого?
преобразуйте десятичное значение в массив байтов, а затем создайте 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));
распределение GUID хорошо, поскольку оно должно быть уникальным...
каков диапазон чисел, используемых для этого? Значение по умолчанию GetHashcode()
реализация Decimal
может принимать во внимание только определенный диапазон значений.