Question

Je suis en train d'écrire des algorithmes qui travaillent sur des séries de données numériques, où parfois, une valeur de la série doit être nulle. Cependant, parce que cette application est la performance critique, j'ai évité l'utilisation de types nullable. J'ai testé les algorithmes perf pour comparer précisément les performances de l'utilisation de types nullables vs types non-nullable, et dans le meilleur des cas types sont nullables 2x plus lent, mais souvent bien pire.

Le type de données le plus souvent utilisé est double, et actuellement la solution choisie pour nulle est Double.NaN. Cependant, je comprends ce n'est pas l'utilisation exacte destinée à la valeur NaN, alors je ne suis pas sûr que il y a des problèmes avec cela, je ne peux pas prévoir et quelle est la meilleure pratique serait.

Je suis intéressé à savoir quelles sont les meilleures alternatives nulles sont les types de données suivants en particulier: à double / flotteur, décimal, DateTime, int / long (bien que d'autres sont plus que bienvenus)

Edit: Je pense que je dois clarifier mes exigences sur le rendement. Gigs de données numériques sont traitées par ces algorithmes à un moment qui prend plusieurs heures. Par conséquent, bien que la différence entre, par exemple 10ms ou 20ms est généralement insignifiante, dans ce scénario, il fait vraiment fait un impact significatif sur le temps.

Était-ce utile?

La solution

Eh bien, si vous avez exclu Nullable<T>, il vous reste des valeurs de domaine - à savoir un nombre magique que vous traitez comme nulle. Bien que ce n'est pas idéal , il est pas rare que ce soit - par exemple, beaucoup des principaux codes-cadre traite DateTime.MinValue le même que nul. Cela déplace au moins les dégâts loin des valeurs communes ...

modifier pour mettre en évidence que si aucune NaN

Alors, où il n'y a pas NaN, peut-être utiliser .MinValue - mais rappelez-vous ce que les maux se produire si vous avez accidentellement utiliser cette même valeur qui signifie le même nombre ...

Il est évident que pour les données non signé dont vous aurez besoin .MaxValue (éviter zéro !!!).

Personnellement, je vais essayer d'utiliser Nullable<T> comme exprimant mon intention plus en toute sécurité ... il peut y avoir des moyens d'optimiser votre code Nullable<T>, peut-être. Et aussi - le temps que vous avez vérifié le nombre magique dans tous les endroits que vous devez peut-être, il ne sera pas beaucoup plus rapide que Nullable<T>

Autres conseils

Je quelque peu en désaccord avec Gravell sur cette affaire de bord spécifique: une variable Null-ed est considérée comme « non défini », il n'a pas de valeur. Donc, tout ce qui est utilisé pour signaler c'est OK: même les nombres magiques, mais avec des nombres magiques vous devez prendre en compte qu'un nombre magique sera toujours vous hanter à l'avenir quand il devient une valeur « valide » tout d'un coup. Avec Double.NaN vous ne devez pas avoir peur pour cela: il ne va jamais devenir un double valide. Bien que, vous devez considérer que NaN dans le sens de la séquence de doubles ne peut être utilisé comme marqueur pour « non défini », vous ne pouvez pas l'utiliser comme un code d'erreur dans les séquences aussi bien, évidemment.

Alors tout ce qui est utilisé pour marquer « non défini »: il doit être clair dans le contexte de l'ensemble des valeurs que cette valeur spécifique est considérée comme la valeur « non défini » et qui ne changera pas à l'avenir.

Si Nullable vous donner trop de problèmes, utilisez NaN, ou tout autre chose, aussi longtemps que vous considérez les conséquences: la valeur choisie représente « non défini » et qui va rester.

Je travaille sur un grand projet qui utilise NaN comme valeur null. Je ne suis pas complètement à l'aise avec elle - pour les mêmes raisons que la vôtre: ne sachant pas ce qui peut aller mal. Nous n'avons pas rencontré de réels problèmes à ce jour, mais être conscient des éléments suivants:

NaN Arithmétique -. Bien que, la plupart du temps, "NaN promotion" est une bonne chose, il ne pourrait pas toujours ce que vous attendez

Comparaison - Comparaison des valeurs devient assez cher, si vous voulez comparer à NaN de même. Maintenant, pour l'égalité flotte test n'est pas simple de toute façon, mais la commande (

Code de l'infection - Je vois beaucoup de code arithmétique qui nécessite un traitement spécifique de NaN de correctes. Donc, vous vous retrouvez avec « fonctions qui acceptent de NaN » et « les fonctions qui ne sont pas » pour des raisons de performance.

Autres non les finis NaN est Nto la seule valeur non finie. Devrait garder à l'esprit ...

Exceptions à virgule flottante ne sont pas un problème quand il est désactivé. Jusqu'à ce que quelqu'un leur permet. Histoire vraie: statique d'un initialisation NaN dans un contrôle ActiveX. Cela ne semble pas effrayant, jusqu'à ce que vous changez d'utiliser l'installation InnoSetup, qui utilise un noyau Pascal / Delphi (?), Qui a des exceptions FPU activées par défaut. Il m'a fallu un certain temps pour comprendre.

Donc, dans l'ensemble, rien de grave, mais je préfère ne pas avoir à considérer NaN souvent.


J'utilise les types nullables aussi souvent que possible, à moins qu'ils soient (avérées) contraintes de performance / Ressource. Un cas pourrait être de grands vecteurs / matrices avec NaN occasionnelle, ou de grands ensembles de valeurs individuelles nommées où le comportement par défaut NaN est correct .


Vous pouvez utiliser un vecteur d'index des vecteurs et des matrices, standard implémentations « matrice clairsemée », ou un bool séparé / vecteur de bits.

réponse partielle:

float et double fournissent NaN (Not a Number). NaN est un peu délicat puisque, par spécification, NaN! = NaN. Si vous voulez savoir si un nombre est NaN, vous aurez besoin d'utiliser Double.IsNaN ().

Voir aussi binaire Floating Point et .NET.

Peut-être la diminution significative des performances se produit lorsque vous appelez l'un des membres de nullables ou propriétés (boxe).

Essayez d'utiliser une struct avec le double + un booléen indiquant si la valeur est spécifiée ou non.

On peut éviter une partie de la dégradation des performances associée à Nullable<T> en définissant votre propre structure

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

Si désiré, on peut définir le constructeur, ou un opérateur de conversion de T à MaybeValid<T>, etc., mais l'utilisation excessive de ces choses peut donner des performances sous-optimales. struct-terrain exposé peut être efficace si l'on évite la copie de données inutiles. Certaines personnes peuvent froncer les sourcils sur la notion de champs exposés, mais ils peuvent être massivement plus efficaces que les propriétés. Si une fonction qui retourne un T aurait besoin d'avoir une variable de type T pour maintenir sa valeur de retour, à l'aide d'un MaybeValid<Foo> augmente simplement par 4 la taille de chose à retourner. En revanche, en utilisant un Nullable<Foo>, il faudrait que la fonction calcule d'abord le Foo puis passer une copie de celui-ci au constructeur pour la Nullable<Foo>. En outre, un retour Nullable<Foo> exigera que tout code qui veut utiliser la valeur retournée doit faire au moins une copie supplémentaire à un emplacement de stockage (variable ou temporaire) de type Foo avant de pouvoir faire quoi que ce soit d'utile. En revanche, le code peut utiliser le champ Value d'une variable de type Foo à peu près aussi efficace que toute autre variable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top