2013-08-25 2 views
-3

Я класс с именем цвета, который реализует следующие переопределения:словарь и Caching

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

Результат Нехорошо, потому что я получаю неправильные пиксели, когда рисую усредненные цвета на экране. Если я возвращаюсь метод к cacheless версии все работает отлично:

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 не является уникальным. Как я могу управлять таким кешем, получая уникальный ключ для средних значений цвета?

+0

Почему именно? D: –

+3

например: почему, по вашему мнению, это подходящий и уникальный ключ ?: Int32 key = left.GetHashCode()^right.GetHashCode()^weight.GetHashCode(); –

+0

Ну, я так не думаю о том, что это производит ... вот почему я пытаюсь найти хорошее решение ... –

ответ

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?
Математика не быстрее, но уменьшает память.

+0

Если бы вы ответили на вопросы, которые я задал, я мог бы улучшить ответ. – Paparazzi

+0

Спасибо за ваш ответ. Ваше решение разумно уменьшило мои столкновения, но я все еще испытываю их. Есть ли у меня какая-либо альтернатива, отличная от использования словаря или вычисления MD5/CRC32 для ключей? –

+0

Повторяю: «Если бы вы ответили на заданные мной вопросы, тогда я мог бы улучшить ответ». Я, конечно, не рекомендовал Tuple. И не спасибо за +1 – Paparazzi