转换System.Decimal到的System.GuidSystem、Decimal、Guid

2023-09-02 21:11:51 作者:盐甜味女孩

我有一个大的字典,其中最关键的是小数,但System.Decimal的GetHash code()是disasterously坏。为了证明我的猜测,我跑了一个for循环100.000 neigboring小数,并检查了分布。使用100.000不同的十进制数只有2个(二!!!)不同的h​​ash codeS。

十进制重新psented为16字节$ P $。就像的Guid!但是的Guid的GetHash code()分布是pretty的好。 我怎么能转换成十进制来的Guid在C#尽可能便宜? 不安全code是OK!

编辑:请求,所以这里的测试是code:

 十进制D =96000000000000000000米;
字典< INT,INT> hashcount =新字典< INT,INT>();
INT长度= 100000;
的for(int i = 0; I<长度;我++)
{
    INT散列code = d.GetHash code();
    INT N;
    如果(hashcount.TryGetValue(哈希code,出N))
    {
        hashcount [散列code = N + 1;
    }
    其他
    {
        hashcount.Add(哈希code,1);
    }
    ð++;
}

Console.WriteLine(hashcount.Count);
 

这将打印7.我不记得了小数点开始给了我2。

解决方案

EXTREMELY哈克解决方案(但可能是最快的)

 公共静态类utils的
{
    [StructLayout(LayoutKind.Explicit)
    结构DecimalGuidConverter
    {
        [FieldOffset(0)]
        公共十进制小数;
        [FieldOffset(0)]
        公众的Guid的Guid;
    }

    私有静态DecimalGuidConverter _CONVERTER;
    公共静态的Guid DecimalToGuid(十进制DEC)
    {
        _converter.Decimal =分解;
        返回_converter.Guid;
    }
    公共静态十进制GuidToDecimal(GUID GUID)
    {
        _converter.Guid = GUID;
        返回_converter.Decimal;
    }
}
 

  //打印000e0000-0000-0000-8324-6ae7b91d0100
Console.WriteLine(Utils.DecimalToGuid((十进制)Math.PI));

//打印00000000-0000-0000-1821-000000000000
Console.WriteLine(Utils.DecimalToGuid(8472米));

//打印8472
Console.WriteLine(Utils.GuidToDecimal(Guid.Parse(00000000-0000-0000-1821-000000000000)));
 
golang float浮点型精度丢失问题解决办法 使用decimal包 float与int的相互转换

I have a big dictionary where the key is decimal, but the GetHashCode() of System.Decimal is disasterously bad. To prove my guess, I ran a for loop with 100.000 neigboring decimals and checked the distribution. 100.000 different decimal numbers used only 2 (two!!!) different hashcodes.

Decimal is represented as 16 bytes. Just like Guid! But the GetHashCode() distribution of Guid is pretty good. How can I convert a decimal to Guid in C# as cheap as possible? Unsafe code is OK!

EDIT: The test was requested, so here is the code:

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);

This prints 7. I do not remember the starting decimal that gave me 2.

解决方案

EXTREMELY HACKY SOLUTION (but probably fastest possible)

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")));