16

これは、他の何よりも「これを説明できますか」というタイプの質問です。

テーブルでNaN値を使用しているときに問題が発生しましたが、テーブルを並べ替えると、非常に奇妙で奇妙な方法で出力されました。NaNが何かを台無しにしていると思ったので、これが本当かどうかを確認するためのテストアプリケーションを作成しました。これが私がしたことです。

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

結果は次のとおりです。

前:

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

後:

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

そうです、NaNはどういうわけか、ソートされた配列を奇妙な方法でソートするようにしました。

フライを引用するには; 「なんでそんなことなの?」

4

5 に答える 5

10

それは

a < NaN == false
a > NaN == false
a == NaN == false

したがって、それらの比較は失敗し、それは全体の種類を捨てます。

于 2011-02-25T23:05:48.767 に答える
6

編集(結論。最終。終了。):これバグです。

double.NaNを含むリストのBug - reportBugin List <double / single> .Sort()[.NET35]を参照して、HansPassantに賛成票を投じてください。.NET4.0がこの配列を.NETとは異なる方法でソートする理由3.5?そこからリンクをリッピングしました。

歴史的考察

[投稿を参照してください:.NET4.0がこの配列を.NET3.5とは異なる方法でソートするのはなぜですか?、うまくいけば、この特定の問題に関するより有用な議論を実際に理解することができます。私もこの回答をクロスポストしました。]

Philが.NET4で指摘した動作は、CompareToで定義された動作です。.NET4のdouble.CompareToを参照してください。これは.NET35と同じ動作ですが、メソッドのドキュメントに従って、両方のバージョンで一貫している必要があります...

Array.Sort(double[]):期待どおりに使用されていないようです。CompareTo(double[])これはバグである可能性があります。以下のArray.Sort(object [])とArray.Sort(double [])の違いに注意してください。以下の説明/訂正をお願いします。

いずれにせよ、>andを使用した回答は、これらの演算子が機能しない理由<を説明していますが、予期しない出力につながる理由を説明できていません。ここに私の発見のいくつかがありますが、それらはわずかかもしれません。==Array.Sort

まず、double.CompareTo(T)メソッドのドキュメント-この順序は、ドキュメントに従って明確に定義されています

ゼロ未満:このインスタンスは値未満です。-または-このインスタンスは数値(NaN)ではなく、値は数値です。

ゼロ:このインスタンスは値と同じです。-または-このインスタンスと値はどちらも数値(NaN)、PositiveInfinity、またはNegativeInfinityではありません。

ゼロより大きい:このインスタンスは値より大きい。-または-このインスタンスは数値であり、値は数値(NaN)ではありません。

LINQPad(3.5と4はどちらも同じ結果になります):

0d.CompareTo(0d).Dump();                  // 0
double.NaN.CompareTo(0d).Dump();          // -1
double.NaN.CompareTo(double.NaN).Dump();  // 0
0d.CompareTo(double.NaN).Dump();          // 1

使用しCompareTo(object)ても同じ結果になります。

0d.CompareTo((object)0d).Dump();                  // 0
double.NaN.CompareTo((object)0d).Dump();          // -1
double.NaN.CompareTo((object)double.NaN).Dump();  // 0
0d.CompareTo((object)double.NaN).Dump();          // 1

だからそれは問題ではありません。

さて、Array.Sort(object[])ドキュメンテーションから- 、、または(ドキュメンテーションによると)の使用はありません><==-ただCompareTo(object)

IComparable配列の各要素の実装を使用して、1次元配列全体の要素を並べ替えます。

同様に、Array.Sort(T[])を使用しCompareTo(T)ます。

配列の各要素のIComparable(Of T)ジェネリックインターフェイス実装を使用して、配列全体の要素を並べ替えます。

どれどれ:

LINQPad(4):

var ar = new double[] {double.NaN, 0, 1, double.NaN};
Array.Sort(ar);
ar.Dump();
// NaN, NaN, 0, 1

LINQPad(3.5):

var ar = new double[] {double.NaN, 0, 1, double.NaN};
Array.Sort(ar);
ar.Dump();
// NaN, 0, NaN, 1

LINQPad(3.5)-アレイCompareToは目的のものであり、動作は契約ごとに「期待される」ことに注意してください。

var ar = new object[] {double.NaN, 0d, 1d, double.NaN};
Array.Sort(ar);
ar.Dump();
// NaN, NaN, 0, 1

うーん。本当に。結論は:

何も思いつきません。

ハッピーコーディング。

于 2011-02-25T23:22:16.613 に答える
1

概念的には、NaNは数値ではないため、数値と比較しても意味がありません。したがって、次のようになります。

a < NaN = false for all a,
a > NaN = false for all a and
NaN != NaN (!)

これを解決するには、IsNaNを使用してNaNをすべての数値よりも小さく(または大きく)して、すべてが並べ替えの一方の端に表示されるようにする独自の比較子を作成する必要があります。

編集:これが比較バージョンのサンプルです:

class Program
{
    private static int NaNComparison(double first, double second)
    {
        if (double.IsNaN(first))
        {
            if (double.IsNaN(second)) // Throws an argument exception if we don't handle both being NaN
                return 0;
            else
                return -1;
        }
        if (double.IsNaN(second))
            return 1;

        if (first == second)
            return 0;
        return first < second ? -1 : 1;
    }

    static void Main(string[] args)
    {
        var doubles = new[] { double.NaN, 2.0, 3.0, 1.0, double.NaN };

        Array.Sort(doubles, NaNComparison);
    }
}
于 2011-02-25T23:11:44.583 に答える
0

実際、奇妙な並べ替え動作は、.NET3.5のバグの結果です。このバグは.NET4.0で解決されました。

これを解決する唯一の方法は、独自のカスタム比較ツールを使用するか、.NET4.0にアップグレードすることです。.NET4.0がこの配列を.NET3.5とは異なる方法でソートする理由を参照してください。

于 2011-02-26T03:16:23.047 に答える
-1

QuickSortアルゴリズムであるデフォルトのソートを使用しているため。実装は不安定なソートを実行します。つまり、2つの要素が等しい場合、それらの順序は保持されない可能性があります

于 2011-02-25T23:09:53.243 に答える