4

配列で最小値と最大値を見つける必要があります(この配列で可能なNaN値を考慮していません)。

これは でのみ簡単に作業できますdoubleが、これらの FindMin および FindMax 関数はジェネリック型で作業する必要があります。

この方法で一般的なNaNをテストしようとしました。

bool isNaN<T>(T value) where T : IEquatable<T>
{
    return !value.Equals(value);
}

しかしEquals、戻っtrueてきますdouble.NaN??!!

今のところ、次のような回避策があります。

bool isNaN<T>(T value) where T : IEquatable<T>
{
    var d = value as double?;
    if (d.HasValue) { return double.IsNaN(d.Value); }

    return !value.Equals(value);
}

私の質問は、最初の解決策が機能しなかった理由を理解することです。これはバグですか?

ここで小さなテストコードを見つけることができます

4

2 に答える 2

7

私は単純に使用double.IsNaNし、必要に応じてコンパイラに暗黙的にfloatメンバーをキャストさせます。

float myFloat = float.NaN; // or 0.0f / 0.0f;
double myDouble = double.NaN; // or 0.0 / 0.0;

Console.WriteLine(double.IsNaN(myFloat));
Console.WriteLine(double.IsNaN(myDouble));

スタック上の非常に少量のメモリを「浪費」し、キャスト op 呼び出しを使用しますが、「数値」NaN を保持できる任意の型に対応するのに十分な汎用性があります。

あるいは、 usingfloat.IsNaNは初歩的なテストで機能するように見えますが、 a の明示的なダウンキャストが必要ですdouble(ダウンキャストは機能しているようdouble.NaN0.0 / 0.0見え、NaN正しく報告されます)。

任意のクリーンな値型のサブセットを一般的に制約することはできません (またはまったく、100% 確実ではありません) ので、<T>個人的にルートを追跡する必要はありません。


呼び出し先が渡されたものを気にする必要がないことを意味する一般的な解決策が必要な場合は、次のことができます。

    static bool IsNaN(dynamic d)
    {
        float dub;

        try
        {
            dub = (float)d;
            return float.IsNaN(dub);
        }
        catch (RuntimeBinderException)
        {
        }

        return false;
    }

ただし、これにはボクシングが発生します。dynamicこれも必須であり、機能しないことに注意してくださいobject。したがって、これも DLR を呼び出します (また、すべてRuntimeBinderExceptionの を飲み込みます)。

于 2012-08-24T12:38:19.800 に答える
6

しかし、Equals は double.NaN に対して true を返します

はい。そして、ジェネリックに関係なく行います:

double x = double.NaN;
Console.WriteLine(x.Equals(x)); // True
Console.WriteLine(x == x); // False

2 行目に False が出力された場合、オーバーライドとIEquatable<T>.Equals矛盾するか、またはの再帰要件に違反する必要があることに注意してください。Equals(object)Equals(object)object.Equals(object)

基本的に、この種のことは、何をするにしても厄介です。

最大/最小値を見つけようとしている場合は、IComparable<T>代わりに使用してみることをお勧めしIEquatable<T>ます - これにより、他の方法で NaN を検出できる可能性があります。(今はチェックする時間がありません。)

于 2012-08-24T12:27:00.983 に答える