12
votes

Énumérable.sum () débordant

Hey, j'utilise le énumérable.sum () méthode d'extension à partir de LINQ pour calculer les codes de hachage, et j'ai un problème avec OverflowExceptions lorsque le code devient grand . J'ai essayé de mettre l'appel dans un bloc non coché , mais cela ne semblait pas aider.

La documentation MSDN pour la méthode indique si la valeur devient trop grosse, mais j'ai vérifié Réflecteur et tout cela est tout ce qu'il y a: xxx

sur la base de cette décompilation, je m'attendrais à ce qu'elle dépasse ou non en fonction du contexte du code d'appel. Pourquoi est-il débordant et comment puis-je le faire arrêter?


4 commentaires

Cela ne répond pas à la question de déborder ... mais si vous utilisez somme pour calculer le code de hachage d'un objet, vous n'allez probablement pas créer de codes de hachage très bien distribués. L'approche typique est quelque chose comme la multiplication par prime-et-gauche-shift-Xor-Suivant dans un contexte décoché.


Ouais, ce n'est pas idéal, mais les codes de hachage que je résume (les codes de hachage de sous-composantes) sont générés d'une manière bien meilleure, donc je ne suis pas si inquiet à ce sujet. (Je ne vient pas d'ajouter int s, où de petits changements ne produiraient pas de code très différent.) Je suppose que ce n'est pas quelque chose que je devrais devenir fou, mais c'est peut-être plus important que moi imaginer...?


Vous pouvez trop déborder avec seulement deux articles - si les hachons de hachage sont à environ32.MaxValue. Puisque vous traitez avec des INT, cela ne devient pas apparent avant d'avoir beaucoup d'articles, mais avec une fonction de hachage correctement distribuée, cela lancera des exceptions plus souvent que non


Vous pouvez aller à


3 Réponses :


9
votes

Le code est en effet exécutant dans un bloc de code C # Bloc. Le problème est que le réflecteur ne décompile pas correctement les blocs cochés et les montre plutôt comme des opérations mathématiques normales. Vous pouvez le vérifier vous-même en créant un bloc vérifié, la compilation du code puis la décompilant dans le réflecteur.

Vous pouvez également vérifier cela en regardant l'IL au lieu du code C # décompilé. Au lieu de l'opcode ADD IL, vous verrez que l'addition se produit avec Add.OVF. Ceci est la version d'ajouter que les lancers sur des débordements xxx

Il n'y a aucun moyen d'obtenir cette méthode particulière pour ne pas lancer trop de débordement. Vos meilleures options sont les suivantes

  1. Basculez sur un type plus grand tel que long
  2. Écrivez votre propre version de Somme qui n'utilise pas l'addition vérifiée

0 commentaires

1
votes

coché ne s'applique qu'aux expressions dans le bloc actuel, et non à une méthode (déjà compilée) appelée. Pour utiliser des mathématiques non cochées, vous devez implémenter votre propre version de somme à l'intérieur d'un non coché bloc


2 commentaires

La distinction cochée / décochée est donc déterminée lors de la compilation? Je m'attendais à ce que ce soit un runtime, selon le contexte, mais je suppose que je me tromperais.


Comme Jareedpar a répondu, il génère différentes commandes IL, que ce soit dans un bloc vérifié ou non coché; vous ne pouvez pas changer déjà-compilé il



7
votes

J'ai écrit cette fonction pour des énumérables génériques. J'aimerais entendre des remarques à ce sujet.

public static int SequenceHashCode<T>(IEnumerable<T> seq)
{
    unchecked
    {
        return seq != null ? seq.Aggregate(0, (sum,obj) => sum+obj.GetHashCode()) : 0;
    }
}


1 commentaires

J'aime ça. Pour autant que je sache, un chèque pour obj == null est manquant.