J'ai un type d'entier, disons Mes premières tentatives étaient quelque chose comme: p>
Mais ces approches et des approches similaires ont toujours des problèmes de certaines valeurs, c'est-à-dire lorsque Remarque: supposons que je travaille en Java où il n'y a pas de conversion implicite en sémantique booléenne et décalée est définie. P> long code>, dont les valeurs sont entre
long.min_value = 0x80 ... 0 code> (-2 ^ 63) et
long .Max_value = 0x7f ... f code> (2 ^ 63 - 1). Je veux hacher avec environ 50% de collision à un entier positif du même type (c'est-à-dire entre 1 et
long.max_value code>) de manière propre et efficace. P>
math.abs (x) + 1 code> li>
(x & long.max_value) + 1 code> li>
ul>
x code> est
0 code> /
long.min_value code> /
/
.Max_value code>. Bien sûr, la solution naïve est d'utiliser 2 déclarations, mais je cherche quelque chose de nettoyant / plus court / plus rapide. Des idées? P>
9 Réponses :
Juste pour m'assurer que vous avez un long et que vous voulez le hisser à un int?
vous pourriez faire ... p> si vous voulez garder une longue chose que vous pourriez faire ... p> si obtenir un 0 n'est pas bon ... p> à fort ... p> Je pense que vous allez avoir besoin d'être correct avec 75% ou d'obtenir un peu laids: P> (x > 0) ? x : (x < 0) ? x & Long.MAX_VALUE : 7
Non, la codomaine de hachage est à nouveau longue - mais elle doit être> 0. Je vais mettre à jour le message pour le rendre plus précis.
Notez que dans l'exemple "laid" 0 collide avec 7.
L'exemple "laid" mappe Min_Value sur 0. et obtient 0 n'est pas bon.
En supposant que vous souhaitiez réduire toutes les valeurs dans l'espace positif, pourquoi pas seulement zéro le piqué de signalisation?
Vous pouvez le faire avec un seul bitwise en profitant du fait que max_value est juste un bit de signe zéro suivi par celles par exemple p> ou pour les longs: p> si vous voulez un "meilleur" hachage avec des qualités pseudo-aléatoires avec des qualités pseudo-aléatoires , vous voulez probablement PSS la valeur à travers une autre fonction de hachage d'abord. My Favor Fast Hays est le Famille Xorshift de George Marsaglia. Ceux-ci ont la belle propriété qu'ils mappent parfaitement l'espace int / long numéro sur lui-même. Vous obtiendrez donc exactement 50% de collision après la mise à zéro du pancarte. P> Voici une implémentation rapide de Xorshift en Java: < / p>
Cela s'effondre à l'espace non négatif, j'ai besoin de s'effondrer de manière positive.
L'approche la plus simple consiste à zéro le piqué de signalisation, puis à mapper zéro sur une autre valeur: Ceci est simple, utilise un seul opérateur si / ternaire et donne environ 50% de collision taux en moyenne. Il y a un inconvénient: il mesure 4 valeurs différentes (0, 42, min_value, min_value + 42) à une seule valeur (42). Donc, pour cette valeur, nous avons 75% de collisions, tandis que pour d'autres valeurs - exactement 50%. P> Il peut être préférable de distribuer des collisions plus uniformes: P> Long y = x + 1 + ((x >> 63) << 1);
Long z = y - (y >> 63);
return z & Long.MAX_VALUE;
Variation, si vous avez la foi dans l'optimiseur: retour (ABS (x) == 0)? 42: ABS (x) code>
@Richardsitze: Il y a un petit problème avec math.abs (). Il donne un résultat négatif pour long.min_value. Mais op a besoin d'un entier positif.
retour (math.abs (x) <1)? 42: math.abs (x)
de la vue théorique des informations, vous avez En tant que tel, la cartographie est triviale avec l'opérateur du module, car elle a toujours un résultat non négatif: p> Cela pourrait être assez coûteux, alors qu'est-ce que c'est possible. ? P> Le math simple pour illustration travaillant avec la cartographie un 4- Bit signé INT Un cours facile est d'avoir Il existe évidemment de nombreuses stratégies. À ce stade, vous pouvez probablement voir une gazzilion. Je vais décrire un seul qui est particulièrement simple. P> let ici Le mappage final est: P > prenant cette logique jusqu'à l'espace 64 bits, vous auriez p> de nombreux autres types de réglage sont possibles dans ce cadre. p> p> 2 ^ 64 code> pour mapper dans
2 ^ 63-1 code> valeurs.
2 ^ 64 = 2 * (2 ^ 63 - 1) + 2 code> Nous aurons deux valeurs de source de mappage de la valeur cible, sauf dans deux cas spéciaux , où trois iront un. Pensez à ceux-ci comme deux valeurs spéciales 64 bits, appelez-les
x1 code> et
x2 code>, que chacun partagez une cible avec deux autres valeurs de source. Dans l'expression code> mod code> ci-dessus, cela se produit par "Emballage". Les valeurs cibles
y = 2 ^ 31-2 code> et
y = 2 ^ 31-3 code> ont trois mappages. Tous les autres ont deux. Puisque nous devons utiliser quelque chose de plus complexe que
mod code> de toute façon, recherchons un moyen de cartographier les valeurs spéciales partout où nous aimons à faible coût p>
x code> dans [-8..7] sur
y code> dans [1..7], plutôt que l'espace 64 bits. P>
x code> dans la carte [1..7], puis le problème diminue à la mappage
x code> dans [- 8..0] à
y code> dans [1..7]. NOTE Il y a 9 valeurs source ici et seulement 7 cibles comme indiqué ci-dessus. P>
y = 1 - x code> pour toutes les valeurs sauf cas spéciaux
x1 == -8 code> et < Code> x2 == -7 code>. Toute la fonction de hachage devient donc p>
s (x) code> est une fonction simple qui dit où
x1 code> et < code> x2 code> sont mappés. Choisissez
s code> en fonction de ce que vous connaissez des données. Par exemple, si vous pensez que les valeurs cibles élevées sont improbables, cartographiez-les sur 6 et 7 avec
S (x) = -1 - x code>. P>
Vous et moi pensons un lot terrible ... j'ai déjà eu des chiffres [-8..7] dans une liste de jouer avec. :)
Je choisirais la version la plus simple, mais pas totalement Temps de gaspillage: Cette implémentation paie une opération conditionnelle pour tous les deux em> les entrées possibles: 0 et min_value. Ces deux sont attribués différentes mappages de valeur avec la deuxième condition. Je doute que vous obtenez une meilleure combinaison de la simplicité (code) et de la complexité (calculationnelle). P> Bien sûr, si vous pouvez vivre avec une distribution pire, il est beaucoup plus simple em>. En limitant l'espace à 1/4 au lieu de 1/2 -1, vous pouvez obtenir: p>
Si la valeur est positive, elle peut probablement être utilisée directement, sinon, toutes les bits: Cependant, vous devez brouiller cette valeur un peu plus si les valeurs de pour certaines constantes positive Une telle solution doit certainement être préférable au lieu d'une "distribution étrange de la collision" pour les mêmes valeurs à chaque fois qu'elle est utilisée. p> p> x code> est corrélé (signification: objets similaires produisent des valeurs similaires pour
x code>), peut-être avec p>
A code> et
B code>, où
a code> doit être assez volumineux et
B code> empêche que
0 code> est toujours mappé à
1 code>. Cela change également le tout à [1, long.max_value] au lieu de [0, long.max_value]. En modifiant les valeurs de
A code> et
B code> Vous pouvez également mettre en œuvre des fonctionnalités de hachage plus complexes telles que Cooko Hashing a besoin de deux fonctions de hachage différentes. p>
Vous pouvez le faire sans conditionnels et dans une seule expression en utilisant l'opérateur de décalage non signé:
Probablement le meilleur moyen d'éviter les conditionnels. Si l'effondrement 4 valeurs dans une seule n'est pas souhaitable, cela peut être prétraité par x + = x >>> 31 code>.
Cela semble le plus simple de tous:
(x % Long.MAX_VALUE) + 1
juste et votre valeur d'entrée avec long.max_value et ou avec 1. rien d'autre n'était nécessaire.
ex: p>
Bonne et simple approche. Seul problème est que trois valeurs très similaires (-1, 0, 1) sont toujours mappées sur la même valeur unique (1).
Je pense que cela reste plus que qualifié pour la collision approximative de 50%, comme indiqué dans la question initiale, oui?