15

一連の数値データで機能するアルゴリズムを作成しています。場合によっては、一連の値を null にする必要があります。ただし、このアプリケーションはパフォーマンスが重要であるため、null 許容型の使用は避けています。アルゴリズムのパフォーマンスをテストして、null 許容型と非 null 許容型を使用した場合のパフォーマンスを具体的に比較しました。最良のシナリオでは、null 許容型は 2 倍遅くなりますが、多くの場合、はるかに劣っています。

最も頻繁に使用されるデータ型は double であり、現在選択されている null の代替は double.NaN です。ただし、これは NaN 値の正確な意図された使用法ではないことを理解しているため、予測できない問題があるかどうか、およびベストプラクティスが何であるかは不明です。

特に次のデータ型に最適な null の代替手段を見つけることに興味があります: double/float、decimal、DateTime、int/long (ただし、他のデータ型は大歓迎です)

編集:パフォーマンスに関する要件を明確にする必要があると思います。数値データのギグは、数時間かかる一度にこれらのアルゴリズムを介して処理されます。したがって、たとえば 10 ミリ秒または 20 ミリ秒の違いは通常は重要ではありませんが、このシナリオでは実際にかかる時間に大きな影響を与えます。

4

6 に答える 6

20

除外した場合Nullable<T>、ドメイン値が残ります。つまり、null として扱うマジック ナンバーです。これは理想的ではありませんが、珍しいことでもありません。たとえば、メインのフレームワーク コードの多くはDateTime.MinValue同じものを null として扱います。これにより、少なくともダメージが一般的な値から遠く離れます...

NaN がない場所のみを強調表示するように編集します

したがってNaN、ない場合は使用するかもしれませんが、同じ数値を意味する同じ値を誤って使用する.MinValueと、どのような問題が発生するかを覚えておいてください...

明らかに、署名されていないデータが必要になります.MaxValue(ゼロは避けてください!!!)。

個人的にはNullable<T>、意図をより安全に表現するために使用しようと思います...Nullable<T>おそらく、コードを最適化する方法があるかもしれません。また、必要なすべての場所でマジック ナンバーを確認した時点で、おそらくNullable<T>?

于 2009-05-18T07:50:26.937 に答える
5

この特定のエッジケースについては、Gravell に同意しません。Null 化された変数は「定義されていない」と見なされ、値がありません。マジック ナンバーでも構いませんが、マジック ナンバーを使用する場合は、マジック ナンバーが突然「有効な」値になったときに、将来常に悩まされることを考慮する必要があります。Double.NaN を使用すると、それを恐れる必要はありません。有効な double になることはありません。ただし、double のシーケンスという意味での NaN は、「未定義」のマーカーとしてのみ使用できることを考慮する必要があります。明らかに、シーケンス内のエラー コードとしても使用できません。

したがって、「未定義」をマークするために使用されるものは何であれ、その特定の値が「未定義」の値と見なされ、将来変更されないことを一連の値のコンテキストで明確にする必要があります。

Nullable で問題が発生する場合は、結果を考慮する限り、NaN などを使用してください。選択された値は「未定義」を表し、そのまま残ります。

于 2009-05-18T08:04:42.123 に答える
5

NaN を値として使用する大規模なプロジェクトに取り組んでいnullます。私はそれに完全に満足しているわけではありません-あなたと同様の理由で、何がうまくいかないのかわからない. これまでのところ実際の問題は発生していませんが、次の点に注意してください。

NaN 算術- ほとんどの場合、「NaN 昇格」は良いことですが、常に期待どおりになるとは限りません。

比較- NaN を等しく比較したい場合、値の比較はかなり高価になります。とにかく、float が等しいかどうかをテストするのは単純ではありませんが、(a < b) の順序付けは非常に見苦しくなります。なぜなら、nan は通常の値よりも小さくする必要がある場合もあれば、大きくする必要がある場合もあるからです。

コードの感染- NaN の特定の処理を正しく行う必要がある算術コードがたくさんあります。したがって、パフォーマンス上の理由から、「NaNを受け入れる関数」と「受け入れない関数」になります。

その他の非有限 NaN は、唯一の非有限値です。心に留めておくべき...

無効にすると、浮動小数点例外は問題になりません。誰かがそれらを有効にするまで。実話: ActiveX コントロールでの NaN の静的初期化。デフォルトで FPU 例外が有効になっている Pascal/Delphi(?) コアを使用する InnoSetup を使用するようにインストールを変更するまで、怖くはありません。理解するのにしばらく時間がかかりました。

したがって、NaN をそれほど頻繁に考慮する必要はありませんが、全体として、深刻なことは何もありません。


パフォーマンス/リソースの制約でない限り、Nullable 型をできるだけ頻繁に使用します。1 つのケースとして、時折 NaN を含む大きなベクトル/行列、またはデフォルトの NaN 動作が正しい名前付きの個々の値の大規模なセットが考えられます。


または、ベクトルと行列のインデックス ベクトル、標準の「疎行列」実装、または個別の bool/bit ベクトルを使用できます。

于 2009-05-18T08:15:39.980 に答える
3

部分的な答え:

Float と Double は NaN (Not a Number) を提供します。NaN は仕様上 NaN != NaN であるため、少し注意が必要です。数値が NaN かどうかを知りたい場合は、Double.IsNaN() を使用する必要があります。

2 進浮動小数点と .NETも参照してください。

于 2009-05-18T08:14:00.030 に答える
0

Nullable<T>独自の構造を定義することで、関連するパフォーマンスの低下の一部を回避できます

struct MaybeValid<T>
{
    public bool isValue;
    public T Value;
}

必要に応じて、コンストラクター、または変換演算子 from TtoMaybeValid<T>などを定義できますが、そのようなものを使いすぎると、最適なパフォーマンスが得られない場合があります。不必要なデータのコピーを回避する場合、公開フィールド構造体は効率的です。一部の人々は、露出したフィールドの概念に眉をひそめるかもしれませんが、それらはそのプロパティを大幅に効率化することができます. a を返す関数がその戻り値を保持するT型の変数を持つ必要がある場合、a を使用すると、返されるもののサイズが単純に 4 増加します。対照的に、 a を使用するには、関数が最初に を計算してから、そのコピーを のコンストラクターに渡す必要があります。さらに、TMaybeValid<Foo>Nullable<Foo>FooNullable<Foo>Nullable<Foo>Foo戻り値を使用するコードは、その値を使用して何かを行う前に、型の格納場所 (変数または一時) に少なくとも 1 つの余分なコピーを作成する必要があります。対照的に、コードはValue、タイプの変数のフィールドをFoo他の変数とほぼ同じくらい効率的に使用できます。

于 2012-12-22T04:24:27.680 に答える
0

Nullable のメンバーまたはプロパティ (ボクシング) の 1 つを呼び出すと、大幅なパフォーマンスの低下が発生する可能性があります。

double + 値が指定されているかどうかを示すブール値を持つ構造体を使用してみてください。

于 2009-05-18T10:01:42.403 に答える