J'ai rencontré cet idiome de programmation récemment:
const float Zero = 0.0;
qui est ensuite utilisé dans les comparaisons:
if (x > Zero) {..}
Quelqu'un peut-il expliquer si cela est vraiment plus efficace ou plus lisible ou maintenable que:
if (x > 0.0) {..}
NOTE: Je peux penser à d' autres raisons pour définir cette constante, je me demande simplement son utilisation dans ce contexte.
x
a le typefloat
,x > 0.0
force la promotion versdouble
, ce qui pourrait être moins efficace. Ce n'est pas une bonne raison d'utiliser une constante nommée, juste pour vous assurer que vos constantes ont le bon type (par exemple0f
,float(0)
oudecltype(x)(0)
).13.37
n'est pasfloat
, ça l'estdouble
. Donc, si vous en vouliez un,float
il est concevable que votre tuteur ait eu raison. Dans certains contextes (par exemple, l'affectation à un flottant)13.37
sera implicitement converti en celuifloat
que vous vouliez, et dans d'autres contextes (par exemple, la déduction de type de modèle), il ne le sera pas, tandis que lestatic const float
commence toujours comme le type que vous vouliez. Par conséquent, plus sûr pour le type. Attention, ce serait le cas13.37f
! Il existe d'autres raisons pour éviter la macro que la "sécurité de type", donc il est tout aussi probable que le tuteur vous donne un mauvais argument.Réponses:
Les raisons possibles sont la mise en cache, la dénomination ou le forçage du type
Mise en cache (non applicable)
Vous voulez éviter le coût de création d'un objet lors de l'acte de comparaison. En Java, un exemple serait
cela implique un processus de création assez lourd et est mieux servi en utilisant la méthode statique fournie:
Cela permet des comparaisons sans encourir de coûts de création répétés car le BigDecimal est pré-mis en cache par la JVM lors de l'initialisation.
Dans le cas de ce que vous avez décrit, une primitive effectue le même travail. Ceci est largement redondant en termes de mise en cache et de performances.
Dénomination (peu probable)
Le développeur d'origine tente de fournir une convention de dénomination uniforme pour les valeurs communes dans tout le système. Cela a un certain mérite, en particulier avec des valeurs rares, mais quelque chose d'aussi basique que zéro n'en vaut la peine que dans le cas du cas de mise en cache plus tôt.
Type de forçage (le plus probable)
Le développeur d'origine tente de forcer un type primitif particulier pour garantir que les comparaisons sont converties en leur type correct et éventuellement à une échelle particulière (nombre de décimales). C'est OK, mais le simple nom "zéro" est probablement un détail insuffisant pour ce cas d'utilisation avec ZERO_1DP étant une expression plus appropriée de l'intention.
la source
typedef
garderaient le type de la variable à un seul endroit et permettraient de le changer sans avoir à modifier le code.0.0f
.byteVar1 = byteVar2 Or CB128
semble un peu plus agréable quebyteVar1 = byteVar2 Or CByte(128)
. Bien sûr, il serait préférable d'avoir un suffixe numérique approprié pour les octets. Étant donné que C # promeut les opérandes de bit à bit aux opérateursint
même lorsque le résultat serait garanti pour tenir dans unbyte
, le problème n'est pas si pertinent là-bas.C'est à cause de "l'outillage lancinant"
Une raison possible que je ne vois pas ici est parce que beaucoup d'outils de qualité signalent l'utilisation de nombres magiques . C'est souvent une mauvaise pratique que de placer des nombres magiques dans un algorithme sans les rendre clairement visibles pour les modifications ultérieures, surtout s'ils sont dupliqués à plusieurs endroits dans le code.
Ainsi, bien que ces outils aient raison de signaler de tels problèmes, ils génèrent souvent des faux positifs pour les situations où ces valeurs sont inoffensives et très probablement statiques, ou simplement des valeurs d'initialisation.
Et lorsque cela se produit, vous êtes parfois confronté au choix de:
À propos des performances
Cela dépend du langage, je suppose, mais cela est assez courant en Java et n'a aucun impact sur les performances, car les valeurs sont alignées au moment de la compilation s'il s'agit de constantes réelles
static final
. Cela n'aurait pas d'impact en C ou C ++ s'ils sont déclarés comme constantes ou même comme macros de pré-processeur.la source
Cela pourrait avoir un sens car il définit explicitement
Zero
comme étant de typefloat
.Au moins en C et C ++, la valeur
0.0
est de typedouble
, tandis que l'équivalent l'float
est0.0f
. Donc, supposer quex
vous vous comparez est également toujours unfloat
dictontout en faisant la promotion
x
dedouble
pour correspondre au type de0.0
ce qui pourrait entraîner des problèmes (avec des tests d'égalité en particulier). La comparaison sans conversion serait bien entenduqui fait la même chose que
Néanmoins, je pense qu'il serait beaucoup plus utile d'activer les avertissements de conversions dans le compilateur au lieu de demander aux utilisateurs d'écrire du code gênant.
la source
Tout d'abord, ici zéro est défini comme
float
nonint
. Bien sûr, cela n'affecte rien dans la comparaison, mais dans d'autres cas, lorsque cette constante est utilisée, cela peut faire la différence.Je ne vois aucune autre raison pour laquelle
Zero
est déclaré une constante ici. C'est juste un style de codage, et il est préférable de suivre le style s'il est utilisé partout ailleurs dans ce programme.la source
Il est presque certainement aussi efficace lors de l'exécution (sauf si votre compilateur est très primitif) et très légèrement moins efficace lors de la compilation.
Quant à savoir si c'est plus lisible que
x > 0
... rappelez-vous qu'il y a des gens qui honnêtement, vraiment, pensent que COBOL était une excellente idée et un plaisir de travailler avec - et puis il y a des gens qui pensent exactement la même chose à propos de C. (La rumeur a il existe même des programmeurs ayant la même opinion sur C ++!) En d'autres termes, vous n'obtiendrez pas d'accord général sur ce point, et cela ne vaut probablement pas la peine de se battre.la source
Si vous écriviez du code générique (c'est-à-dire non spécifique au type), alors très probablement. Une
zero()
fonction peut s'appliquer à tout type algébrique ou à tout type qui est un ajout par groupe. Ce pourrait être un entier, ce pourrait être une valeur à virgule flottante, ce pourrait même être une fonction si votre variable est, par exemple, elle-même une fonction dans un espace linéaire (par exemple x est une fonction linéaire de la forme z -> a_x * z + b_x) etzero()
fournit ensuite la fonction avec a et b étant tous deuxzero()
du type sous-jacent.Donc, vous vous attendez à un tel code dans, disons, C ++ éventuellement (bien que a
zero()
ne soit pas très courant AFAIK), ou dans Julia, et peut-être dans d'autres langages.la source