-3

我有一个名为 Color 的类,它实现了以下覆盖:

public override Int32 GetHashCode()
{
    unchecked
    {
        Int32 hash = 23;
        hash = (hash * 37) + m_Changes.GetHashCode();
        hash = (hash * 37) + m_Blue;
        hash = (hash * 37) + m_Green;
        hash = (hash * 37) + m_Random;
        hash = (hash * 37) + m_RandomBlue;
        hash = (hash * 37) + m_RandomGreen;
        hash = (hash * 37) + m_RandomRed;
        hash = (hash * 37) + m_Red;

        return hash;
    }
}

我正在尝试缓存结果以减少计算:

public static Color Average(Color left, Color right, Double weight)
{
    Color value;
    Int32 key = left.GetHashCode() ^ right.GetHashCode() ^ weight.GetHashCode();

    if (!s_Averages.TryGetValue(key, out value))
    {
        Double complement = 100.0 - weight;

        Int32 red = (Int32)(((left.Red * complement) + (right.Red * weight)) / 100.0);
        Int32 green = (Int32)(((left.Green * complement) + (right.Green * weight)) / 100.0);
        Int32 blue = (Int32)(((left.Blue * complement) + (right.Blue * weight)) / 100.0);
        Int32 random = (Int32)(((left.Random * complement) + (right.Random * weight)) / 100.0);
        Int32 randomRed = (Int32)(((left.RandomRed * complement) + (right.RandomRed * weight)) / 100.0);
        Int32 randomGreen = (Int32)(((left.RandomGreen * complement) + (right.RandomGreen * weight)) / 100.0);
        Int32 randomBlue = (Int32)(((left.RandomBlue * complement) + (right.RandomBlue * weight)) / 100.0);

        value = new Color(red, green, blue, randomRed, randomGreen, randomBlue, random, (left.Changes || right.Changes));
        s_Averages.Add(key, value);
    }

    return value;
}

结果不好,因为我在屏幕上绘制平均颜色时得到了错误的像素。如果我将该方法恢复为无缓存版本,一切正常:

public static Color Average(Color left, Color right, Double weight)
{
    Double complement = 100.0 - weight;

    Int32 red = (Int32)(((left.Red * complement) + (right.Red * weight)) / 100.0);
    Int32 green = (Int32)(((left.Green * complement) + (right.Green * weight)) / 100.0);
    Int32 blue = (Int32)(((left.Blue * complement) + (right.Blue * weight)) / 100.0);
    Int32 random = (Int32)(((left.Random * complement) + (right.Random * weight)) / 100.0);
    Int32 randomRed = (Int32)(((left.RandomRed * complement) + (right.RandomRed * weight)) / 100.0);
    Int32 randomGreen = (Int32)(((left.RandomGreen * complement) + (right.RandomGreen * weight)) / 100.0);
    Int32 randomBlue = (Int32)(((left.RandomBlue * complement) + (right.RandomBlue * weight)) / 100.0);

    return (new Color(red, green, blue, randomRed, randomGreen, randomBlue, random, (left.Changes || right.Changes)));
}

这只能意味着我使用 GetHashCode 生成的密钥不是唯一的。如何管理这种缓存,为我的颜色平均值获取唯一键?

4

1 回答 1

1

在这种情况下,我不认为你会得到一个唯一的密钥
但是你可以做得更好
如果你左右切换你会得到相同的密钥,这会受到影响。

Int32 key = left.GetHashCode() ^ right.GetHashCode() ^ weight.GetHashCode();
15 ^ 17 ^ 20 == 17 ^ 15 ^ 20

这将减少关键冲突

Int32 key = 17*left.GetHashCode() ^ 23*right.GetHashCode() ^ weight.GetHashCode();

更好的是可以使用 UInt64 键

UInt64 key = (((UInt64)left.GetHashCode() << 32) | (UInt64)right.GetHashCode()) ^ ((UInt64)weight.GetHashCode() << 30);

看看你的平均水平。
所有这些颜色都在计算中被转换为 Double 并且有开销。
必须精确到什么程度?
如果权重和补码是 Int32 会有一些舍入误差,但它会更快。

Int32 iweight = (Int32)(weight*100);   
Int32 icomplement = 10000 - weight;
Int32 red = ((left.Red * icomplement) + (right.Red * iweight)) / 10000;

同样,这会有一些舍入误差,但会更快。

为什么要使用 Int32?
UInt16 或 Byte 就足够了吗?
数学并不快,但会减少记忆。

于 2013-08-25T14:27:16.627 回答