Eclipse 3.5 dispose d'une fonctionnalité très intéressante permettant de générer des fonctions Java hashCode(). Il génère par exemple (légèrement raccourci :)
class HashTest {
int i;
int j;
public int hashCode() {
final int prime = 31;
int result = prime + i;
result = prime * result + j;
return result;
}
}
(Si vous avez plus d'attributs dans la classe, result = prime * result + attribute.hashCode();
est répété pour chaque attribut supplémentaire. Pour les ints, .hashCode() peut être omis).
Cela semble bien mais pour le choix 31 pour la prime. Il est probablement tiré du implémentation de hashCode de Java String qui était utilisé pour des raisons de performances qui ont disparu depuis l'introduction des multiplicateurs matériels. Ici, il y a de nombreuses collisions de codes de hachage pour de petites valeurs de i et j : par exemple, (0,0) et (-1,31) ont la même valeur. Je pense que c'est une mauvaise chose (TM), puisque les petites valeurs se produisent souvent. Pour String.hashCode, vous trouverez également de nombreuses chaînes courtes avec le même hashcode, par exemple "Ca" et "DB". Si vous prenez un grand nombre de valeurs premières, ce problème disparaît si vous choisissez bien la valeur première.
Ma question est donc la suivante : quel est le bon prime à choisir ? Quels critères appliquez-vous pour le trouver ?
Il s'agit d'une question d'ordre général - je ne souhaite donc pas donner une fourchette pour i et j. Mais je suppose que dans la plupart des applications, les valeurs relativement petites sont plus fréquentes que les grandes. () Cela ne fait peut-être pas une grande différence, mais un meilleur choix est un moyen facile et évident d'améliorer la situation - alors pourquoi ne pas le faire ? Lang Commons HashCodeBuilder suggère également des valeurs curieusement petites.
( Clarification C'est pas un duplicata de Pourquoi la fonction hashCode() de Java dans String utilise-t-elle 31 comme multiplicateur ? puisque ma question ne porte pas sur l'historique de la 31 dans le JDK, mais sur ce qui serait une meilleure valeur dans un nouveau code utilisant le même modèle de base. Aucune des réponses qui s'y trouvent ne tente de répondre à cela).
4 votes
31 est toujours bon car il n'implique pas nécessairement le chargement d'une constante. Sur un processeur ARM (au moins celui utilisé par environ 99,9997% des téléphones mobiles)
*31
peuvent être donnés en une seule instruction. En réalité, tout nombre impair, premier ou non, est suffisant.0 votes
Je pensais aux programmes de bureau, où il importe peu de choisir 31 ou 1327144003. Curieusement, sur ma machine, la multiplication avec 31 est en fait un peu plus lente - probablement une optimisation qui a mal tourné. 8-)
8 votes
Primes de forme
p = (2^n-1)
se prêtent à l'optimisation dex * p = (p << n) - p
ce que le compilateur fait généralement. Tiré de Joshua Bloch, Effective Java, chapitre 3, point 9. Question sur le SO stackoverflow.com/questions/299304/0 votes
Et les multiplications avec des entiers <128 ont un boost supplémentaire dans jvm
2^n-1
, prime, petit cela donne 31.0 votes
@corsiKa Comme je l'ai dit, pour les machines de bureau actuelles, cela ne semble plus être une optimisation - le temps est le même. Pire encore : sur ma machine, la multiplication avec 31 était un peu plus lente - peut-être que la JVM a essayé de l'"optimiser" en calculant x << 5 - x, et cela est en fait plus lent que l'utilisation du multiplicateur matériel.
0 votes
Hans-PeterStörr Sur i86, il y a une différence, car il existe un mode pour une opérande immédiate d'un seul octet. Vous obtenez une instruction plus courte et dans un benchmark que j'ai écrit il y a des années, elle était légèrement plus rapide.
2 votes
@MarkRotteveel Veuillez noter que cette question est tout à fait différente de [Pourquoi la fonction hashCode() de Java dans String utilise-t-elle 31 comme multiplicateur ?][1] puisqu'il ne s'agit pas de l'histoire de 31, mais de ce qui serait un meilleur choix au lieu d'utiliser 31, sans utiliser de bibliothèques supplémentaires ou des méthodes entièrement différentes de calcul des hachages. Aucune des réponses ne répond à cette question. [1] : stackoverflow.com/questions/299304/