-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 に答える