45 votes

Pourquoi ne .NET 4.0 trier ce tableau différemment .NET 3.5?

Cette stackoverflow question soulève une question intéressante sur le tri des doubles des tableaux avec des valeurs NaN. L'OP a affiché le code suivant:

static void Main(string[] args)
{
    double[] someArray = { 4.0, 2.0, double.NaN, 1.0, 5.0, 3.0, double.NaN, 10.0, 9.0, 8.0 };

    foreach (double db in someArray)
    {
        Console.WriteLine(db);
    }

    Array.Sort(someArray);
    Console.WriteLine("\n\n");
    foreach (double db in someArray)
    {
        Console.WriteLine(db);
    }

    Console.ReadLine();
}

Lorsque vous exécutez ce dans le cadre du .NET framework 3.5, le tableau est trié comme suit:

1,4,NaN,2,3,5,8,9,10,NaN

Lorsque vous l'exécutez .NET 4.0, le tableau est trié un peu plus logiquement:

NaN,NaN,1,2,3,4,5,8,9,10

Je peux comprendre pourquoi il ne sorte bizarrement .NET 3.5 (NaN parce que n'est pas égale, inférieure ou supérieure, n'importe quoi). Je peux aussi comprendre pourquoi il ne sorte de la façon dont il le fait .NET 4.0. Ma question est, pourquoi ce changement de 3.5 à 4.0? Et où est la documentation de Microsoft pour ce changement?

39voto

Hans Passant Points 475940

C'est une correction de bug. Le rapport de rétroaction avec le bug de détails est ici. La réponse de Microsoft pour le rapport de bug:

Notez que ce bug affecte les éléments suivants:

  • Tableau.Sort(), où la matrice contient le Double.NaN
  • Tableau.Sort(), où la matrice contient une Seule.NaN
  • tous les appelants de ci-dessus, par exemple sur la Liste.Sort(), où la liste contient le Double.NaN

Ce bug sera corrigé dans la prochaine version majeure de l'exécution; d'ici là, vous pouvez contourner ce problème en utilisant une mesure IComparer qui ne le tri correct. Comme mentionné dans la solution de contournement des commentaires, n'utilisez pas de Comparer.Par défaut, parce que c'est spécial-emballé avec un raccourci de la routine de tri qui ne gère pas NaN correctement. Au lieu de cela, vous pouvez fournir votre propre comparateur fournit un équivalent de comparaison, mais ne pas l'être tubés.

6voto

Thomas Levesque Points 141081

Pas vraiment une réponse, mais peut-être un indice... Vous pouvez reproduire le bizarre 3.5 comportement en 4.0 avec ce code:

void Main()
{
    double[] someArray = { 4.0, 2.0, double.NaN, 1.0, 5.0, 3.0, double.NaN, 10.0, 9.0, 8.0 };
    Array.Sort(someArray, CompareDouble);
    someArray.Dump();
}

int CompareDouble(double a, double b)
{
    if (a > b)
        return 1;
    if (a < b)
        return -1;
    return 0;
}

Ici, les deux a > b et a < b return false si a ou b est - NaN, de sorte que l' CompareDouble méthode retourne 0, NaN est considéré comme l'égal de tout... Cela donne le même résultat qu'en 3.5:

1,4,NaN,2,3,5,8,9,10,NaN

2voto

Jim Mischel Points 68586

Je n'ai pas le code pour le .NET 3.5 de l'exécution pour vérifier cela, mais je pense qu'ils correction d'un bug dans le comparateur par défaut pour double de la mettre en conformité avec la documentation.

Selon ce document, Double.Compare friandises NaN comme égal à PositiveInfinity et NegativeInfinity, et moins que tout autre valeur.

La documentation est la même pour .NET 3.5 et .NET 4.0, donc je pense que c'était un bug fix pour rendre le code du travail tel que documenté.

EDIT:

Après avoir lu les commentaires dans la question, je pense que le problème n'était pas en Double.Compare, mais plutôt en quelle que soit la méthode Array.Sort (qui est ce que l' List.Sort dépend) pour comparer Double valeurs. D'une certaine manière, je ne pense pas que c'est vraiment Double.Compare.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X