Dans les langues qui n'autorisent pas les traits de soulignement dans les constantes de nombre entier, est-ce une bonne pratique de créer une constante pour 1 milliard de dollars?

39

Dans les langues qui n'autorisent pas les traits de soulignement dans les littéraux entiers , est-ce une bonne idée de créer une constante pour 1 milliard? par exemple en C ++:

size_t ONE_BILLION = 1000000000;

Certes, nous ne devrions pas créer de constantes pour les petits nombres comme 100. Mais avec 9 zéros, il est sans doute facile de laisser un zéro ou d’en ajouter un supplémentaire dans le code suivant:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;
Martin C. Martin
la source
24
J'espère que tout le monde ici vote pour NON . De cette façon, peut-être qu'un jour ma banque transférera un milliard de dollars sur mon compte, car un programmeur n'a pas utilisé une constante et égaré un zéro! :)
Réactif
43
Pourquoi ne pas créer des constantes pour de petits nombres? Que signifie 100? À moins qu'il y ait un contexte, c'est un nombre magique.
Allan
4
@MathewFoscarini En général, les erreurs peuvent aller dans les deux sens. Mais quand il s'agit de votre banque, les erreurs vont toujours à votre encontre.
emory
23
Pensez à écrire 1e9, 10^9ou 1_000_000_000si la langue que vous utilisez le supporte.
Hammar
5
Milliards ou à grande échelle ?
Rvalue

Réponses:

33

La plupart des langues comportent une sorte de notation exponentielle. Un million est 1e6, (ce qui signifie 1 fois 10 à la puissance de 6). Cela résout le problème encore mieux que la plupart des propositions présentées ici.

Dans beaucoup de langages de type C, la notation scientifique définit cependant un type à virgule flottante , ce qui est regrettable si vous avez vraiment besoin d'un int. Cependant, vous pouvez facilement transtyper cette constante pour éviter les conversions implicites dans votre formulaire.

n / int(1e9) diviserait par un milliard.

Dans votre exemple, traitant des quantités physiques (temps en nanosecondes), je me demanderais généralement si le nombre entier est le bon type. En fait, une virgule flottante doubleconviendrait mieux pour traiter des quantités mesurables (bien qu’il existe bien sûr des cas où vous préféreriez a long long).

Wirrbel
la source
6
Je pense que la solution NANOSECONDS_IN_ONE_SECOND est beaucoup plus claire et ordonnée.
Thomas Bonini
1
La question concernait les libéraux entiers et je propose d'utiliser la notation scientifique. Que ce soit en place ou en définissant une constante est une question de code structurant qui n'a pas été demandé dans la question. Définir une constante ajoute une abstraction limitée, j'écrirais une fonction / macro de conversion pour obtenir une meilleure abstraction
wirrbel
1
Jeter un très grand double sur un int risquerait-il les problèmes de différence d'arrondi typiques des nombres en virgule flottante?
Philipp
avec des types entiers de précision normale, cela ne devrait pas poser de problème tant que vous utilisez un float à double précision pour effectuer la conversion. vous avez raison lorsque vous utilisez les valeurs de la long longplage.
Wirrbel
145

Créez-en un nommé NANOSECONDS_IN_ONE_SECOND à la place de ce qu'il représente.

Ou un nom plus court, mieux si vous pouvez penser à un.

JohnB
la source
58
Je dirais Nanoseconds_Per_Secondmais c'est, à mon avis, la bonne réponse.
KChaloux
8
@ Matthew je ne comprends pas votre point. Il n'y a rien de mal à dire millimètres par mètre. Vous pensez peut-être que c'est redondant, dans cette nanoseconde MOYENS un milliard de fractions de seconde, mais rien de mal à le répéter. C'est comme si on disait 1 + 1 = 2. "x par y" continue à avoir plus de sens quand x et y sont disjoints, comme "unités par demi-douzaine" ou "nanosecondes par milliseconde"
Mark Canlas
7
@MathewFoscarini En fait, non, dans ce contexte, ce n'est pas le cas. Si c'était le cas, une constante nommée NANOSECONDSn'a pas de sens car vous ne pouvez pas dire à quoi elle est censée s'appliquer. De même, NANOSECONDS_PER_MICROSECONDest une constante valide similaire qui a du sens.
Izkata
5
@MathewFoscarini, "millimètres par mètre" est un moyen de supprimer l'unité de la conversion pour obtenir la valeur brute. 1mm/1m = 1000, ce qui est exactement le point de ce qui se fait ici.
ZzzzBov
11
Pourquoi tant de frappe? NS_PER_SECdevrait être évident pour quiconque devrait traiter avec des nanosecondes.
Rex Kerr
67

Les constantes sont censées donner un sens aux nombres. Il n'y a pas de signification supplémentaire ONE_BILLIONà 1000000000. En fait, cela rend les choses plus confuses, car dans des langages naturels différents, un milliard signifie quelque chose de différent (un milliard ou un million de millions)! Si vous voulez l'écrire plus court, il est probable que votre langage de programmation autorise l'utilisation de la notation scientifique, c'est-à-dire 1e9. Sinon, je suis d'accord avec @JohnB, que ce nombre signifie vraiment le nombre de nanosecondes en une seconde, nommez-le ainsi.

Thijs van Dien
la source
9
Il est bon de noter que des milliards de langues différentes signifient différentes quantités de zéros
frozenkoi
3
suggérerait de changer les langues ordinaires en langues naturelles. régulier veut dire autre chose ...
jk.
Différentes interprétations de "milliards" dans les langues un si bon point! Pourquoi ne puis-je pas voter votre réponse deux fois!
DSF
3
Vous n'avez pas besoin de langues différentes. Vous n'avez même pas besoin de pays différents. En anglais britannique, "milliards" signifie quelque chose de différent avant et après 1974 dans les communications officielles (médias et gouvernement) et les deux usages existent toujours.
Jörg W Mittag
1
" Il n'y a pas de signification supplémentaire dans ONE_BILLION à 100000000000000 .. Je ne suis pas d'accord. (Indice: je vous ai délibérément mal cité et j'ai ajouté un autre zéro; l'aurais remarqué si je ne l'avais pas mentionné?)
Keith Thompson
27

Pour un ou deux usages, j'utiliserais la convention:

tv_sec = timeInNanosec / (1000 * 1000 * 1000);
tv_nsec = timeInNanosec % (1000 * 1000 * 1000);

C'est parfaitement explicite, compilé à une constante et il est difficile de bousiller.

En outre, il est très utile dans des cas tels que:

var Time = 24 * 60 * 60;

où il est facile de voir que nous parlons d'un jour en quelques secondes.

Sklivvz
la source
C'est ce que je fais d'habitude. Cela a aussi l’avantage de ne pas oublier que j’ai défini NANOSECONDS_IN_ONE_SECOND hier et que je définis aujourd'hui NANOSECONDS_PER_SECOND. Et peut-être ONE_AMERICAN_BILLION demain.
Thomas Padron-McCarthy
Assurément, 'SecondsInOneDay = 24 * 60 * 60' est encore plus facile?
JBRWilkinson
@JBRWilkinson bien sûr, mon extrait de code initial utilisait un cours instance.Time = ..., mais je l'ai ensuite rendu muet ...
Sklivvz
3
En C ou C ++, (1000 * 1000 * 1000)est de type int, qui ne doit comporter que 16 bits, de sorte qu'il peut déborder. Vous pouvez écrire (1000L * 1000L * 1000L)pour éviter cela.
Keith Thompson
Je le fais beaucoup. Il fonctionne très bien.
vy32
10

La longueur de la valeur n'est pas ce qui définit si une constante est nécessaire ou non.

Vous utilisez des constantes pour éviter les nombres magiques , pas pour éviter de taper.

Par exemple, ce sont des constantes parfaitement valides:

public static final int CLOSE_CURSORS_AT_COMMIT = 1;
public static final int CONCUR_READ_ONLY = 2;
public static final int CONCUR_UPDATABLE = 3;
public static final int FETCH_FORWARD = 4;
public static final int FETCH_REVERSE = 5; 
public static final int FETCH_UNKNOWN = 6;
public static final int HOLD_CURSORS_OVER_COMMIT = 7;
public static final int TYPE_FORWARD_ONLY = 8;
public static final int TYPE_SCROLL_INSENSITIVE = 9;
public static final int TYPE_SCROLL_SENSITIVE = 10;

Utilisation:

public static final int NANOSECS_PER_SECOND = 1000000000;

(les exemples de code sont en Java, traduisez dans votre langue préférée)

Tulains Córdova
la source
3
+1 Les numéros nommés sont presque inutiles. Le but des constantes est de donner un sens à ces nombres. Que représentent-ils? Que comptent-ils ou limitent-ils ou nomment-ils officiellement? Pas quelle est la valeur du compte.
JustinC
2
Ce sont des exemples terribles de constantes valides. Ils auraient dû être des enums, sauf qu'ils ont été créés avant les enums.
Christoffer Hammarström
@ ChristofferHammarström Ils ont en effet été créés avant les énumérations, ils font partie de la classe ResultSet, dans le package SQL du SDK Java.
Tulains Córdova
2
@ ChristofferHammarström Ils sont mauvais parce que maintenant nous avons des énumérations mais pas pour ne rien dire. Enum n'existait pas quand ces classes ont été créées et pour différencier les options mutuellement exclusives telles que FETCH_FORWARD et FETCH_REVERSE, leur donne une valeur différente. La valeur n'a pas d'importance, juste le fait qu'ils soient différents.
Tulains Córdova
8

Un milliard américain ou européen?

(ou en termes techniques, un milliard à court terme ou à long terme - l'un est égal à 1000 millions, l'autre à un million).

Étant donné cette confusion, alors je dirais oui - il est logique de la définir une fois et de la conserver, elle s'applique également à toute constante sur laquelle vous devez accepter la définition - définissez-la une fois.

gbjbaanb
la source
17
"Un milliard américain ou européen?" - "Quoi? Je ne le sais pas! Ahhhhh !!!!"
Tesserex
Au Royaume-Uni, du moins, nous avons depuis longtemps adopté le 1e milliard.
Jack Aidley
1
@ Tesserex - eh bien, vous devez savoir ces choses quand vous êtes roi.
gbjbaanb
5

Raisons pour ne pas

Tout d'abord, voici une raison pour ne pas écrire de soulignement ou utiliser une astuce pour le simuler: cela rend les constantes plus difficiles à trouver dans le code. Supposons que certains programmes présentent, quelque part dans leur fonctionnement, la valeur codée en dur 1500000 pour un paramètre donné. Je veux savoir où cela se produit réellement dans le code source du programme. Je recherche donc le code 1500000et ne trouve rien. Pourquoi? Pourrait-il être en hexadécimal (mais pourquoi pour un nombre décimal aussi rond). À l'insu de moi, la constante est en fait écrite comme 1_500_000. J'avais besoin de la regex 1_?500_?000.

Caractères guides en commentaire

Ce n’est pas parce qu’un type d’aide visuelle n’est pas disponible ou si nous ne souhaitons pas l’utiliser pour les raisons susmentionnées que nous ne pouvons pas tirer parti des deux dimensions du fichier texte pour créer un autre moyen d’affichage:

foo = bar / 1000000000;
//           --^--^--^  

Avec cela, nous pouvons facilement nous convaincre qu'il existe trois groupes de trois zéros. Cependant, nous pouvons toujours rechercher le code source 1000000000et le trouver.

Coloration de la syntaxe

Un éditeur de texte avec coloration de syntaxe programmable peut être utilisé pour colorer les groupes de chiffres en constantes numériques avec des couleurs alternées pour une meilleure lisibilité. Nous n'avons rien à faire dans le code.

Prétraitement: C, C ++, Objective C

Maintenant, si nous voulons vraiment des virgules entre les chiffres, en C et C ++, nous pouvons utiliser un prétraitement:

/* Four digit base TH-ousand constant macro */
/* Condensed using Horner's rule */
#define TH(A,B,C,D) ((((((A) * 1000) + (B)) * 1000) + (C)) * 1000 + D)

tv_sec = nanoseconds / TH(1,000,000,000)

Fonctionne pour les nombres comme TH(1,234,567,890).

Une macro similaire à TH peut également fonctionner avec un collage de jetons plutôt que de l'arithmétique. Dans le préprocesseur C, l’ ##opérateur binaire ("token paste") peut être utilisé dans un corps de macro afin de coller ensemble deux opérandes dans un seul jeton. Un ou les deux opérandes peuvent être des macro-arguments. L'inconvénient ici (créer un risque pour nous) est que si la caténation résultante n'est pas un jeton valide, le comportement n'est pas défini.

#define TOK4(A, B, C, D) A ## B ## C ## D

À présent

TOK4(1,000,000,000)       /* produces the single token 1000000000 */
TOK4(1,123,000,000.0E+2)  /* produces the single token 1123000000.0E+2 */
TOK4(pr,in,t,f)           /* produces the token printf */
TOK4(#,*,a,b)             /* undefined behavior, #*ab is not valid token syntax */

Les programmes C qui collent ensemble des identificateurs et utilisent les résultats pour nommer des variables et des fonctions globales existent et sont terribles, car ils sont insensibles aux outils tels que GNU id-utils et ctags.

Kaz
la source
2
+1 pour l'un des meilleurs abus du pré-processeur que j'ai vu. J'irais quand même avec NSEC_PER_SEC ou quelque chose en production, cependant.
Victor
Très près de -1 pour avoir abusé du préprocesseur :)
un CVn
3

Oui, cela semble être une idée raisonnable. Les erreurs DIGIT off-by-one sont encore pires que les fameuses erreurs off-by-one. Bien que cela puisse créer de la confusion pour que d’autres personnes (y compris votre futur individu) lisent le code.

Un nom plus explicatif, tel que NANOSEC_PER_SEC, semble bien, car cela ajouterait de la clarté là où il est utilisé pendant un certain temps. Cependant, cela n'a aucun sens d'utiliser dans des contextes autres que le temps, et il ne serait pas pratique de créer un milliard distinct pour chaque situation.

Ce que vous voulez vraiment faire, aussi stupide que cela puisse paraître, au début, est de «diviser sur une seconde». Cela laisse NANO_PER, non seulement indépendant de la langue (10 ^ 9 en Amérique et en Europe), mais également indépendant de la situation (aucune limitation sur les unités), et il est facile à saisir et à lire.

MegaWidget
la source
Cet article est plutôt difficile à lire (mur de texte). Pourriez - vous l' esprit modifier ing dans une meilleure forme?
Gnat
3

En général, il est déconseillé d’utiliser des constantes scalaires pour les conversions d’unités et si vous vous trouvez en train de faire des constantes pour de telles choses, vous effectuez des conversions beaucoup trop souvent.

Lorsque vous avez une quantité d'une unité (disons 10 secondes) et que vous souhaitez convertir en une autre unité (c.-à-d. En nanosecondes); C'est précisément le moment d'utiliser le système de typographie de votre langue pour vous assurer que les unités sont réellement mises à l'échelle comme vous le souhaitez.

Faites votre fonction prend un Nanosecondsparamètre, et fournir aux opérateurs de conversion et / ou constructeurs dans cette catégorie pour Seconds, Minutesou ce que vous voudrez. C’est là que votre const intou #defineou que vous 1e9voyez dans d’autres réponses appartient.

Cela évite d'avoir des variables d'unités ambiguës flottant autour de votre code; et empêche des pans entiers d'insectes d'où la mauvaise multiplication / division a été appliquée, ou était déjà appliquée, ou si la quantité était en réalité la distance au lieu du temps, ou ...

En outre, dans de telles classes, il est bon de construire une construction à partir de scalarsprivate et d'utiliser un "MakeSeconds (int)" statique ou un moyen similaire afin de décourager l'utilisation négligée de nombres opaques.

Plus spécifiquement pour votre exemple, en C ++, consultez Boost.Chrono .

rvalue
la source
1
+ À tout le moins, utilisez un type commun avec un facteur de mise à l'échelle ou de décalage basé sur une base similaire au fuseau horaire souvent décrié.
JustinC
1

Personnellement, je ne considérerais pas comme une bonne pratique de créer une constante à moins que ce ne soit une constante. S'il doit se trouver à plusieurs endroits et qu'il soit défini en haut du fichier pour modification / ou test va être utile, alors absolument.

Si c'est juste parce que c'est difficile à taper? alors non.

Personnellement, si le code de quelqu'un d'autre est défini avec une constante, je considère généralement qu'il s'agit d'un aspect important du code. Par exemple, tcp maintient les minuteries en vie, nombre maximal de connexions autorisées. Si je devais le déboguer, je ferais probablement beaucoup d’attention inutile pour essayer de comprendre pourquoi / où il était utilisé.

Simon McLoughlin
la source
Je comprends la blague, mais si les programmeurs de banque devaient créer une constante pour chaque numéro, le transfert du logiciel serait gigantesque, ingérable et lent. Je ne pouvais qu'imaginer à quoi cela ressemblerait, imaginez-vous qu'il faudrait 3 jours ouvrables pour virer de l'argent à ... OH MON DIEU, CELA-LE !!!
Simon McLoughlin
Il faut 3 jours à ma banque pour virer de l’argent :(
Réactif
1
@MathewFoscarini les banquiers utilisent Excel, ils n'ont pas besoin de programmeurs;)
Mateusz
@Simon En fonction du langage et du compilateur, les constantes doivent être optimisées dans le code, entraînant une légère surcharge. Je comprends votre point de vue, mais les constantes peuvent être utilisées partout où utiliser un nom au lieu d’un nombre magique pourrait améliorer la lisibilité du code.
Steven
Difficile à lire est beaucoup plus un problème qu’il est difficile à taper.
Alb
0

Lorsque vous réfléchissez à la raison pour laquelle vous avez inscrit "1 milliard" au lieu de "1000000000" dans le titre de votre question, vous comprendrez pourquoi la réponse est oui.

Alb
la source
0

Ne créez pas une constante pour vos gros littéraux. Vous auriez besoin d'une constante pour chaque littéral de ce type, qui est (à mon avis) une blague complète. Si vous avez désespérément besoin de clarifier vos littéraux sans l'aide d'éléments tels que la coloration syntaxique, vous pouvez (bien que ce ne soit pas le cas) créer des fonctions ou des macros pour vous rendre la vie "plus facile":

#define SPLIT3(x, y, z) x##y##z

int largeNumber1 = SPLIT3(123,456,789);
int largeNumber2 = 123456789;
Thomas Eding
la source
0

Je voudrais faire ceci:

const int Million = 1000 * 1000;
const int Billion = 1000 * Million;

ou

const int SciMega = 1000 * 1000; const int SciGiga = 1000 * SciMega;

En ce qui concerne le nombre de nanosecondes par seconde: nano est "l'inverse" du giga.

Kilo  Mega  Giga   etc.
10^3  10^6  10^9
Milli Micro Nano   etc.
10^-3 10^-6 10^-9

Notez le "Sci" - pour scientifique, comme dans les ordinateurs, les significations de kilo, méga, giga etc. sont différentes: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20), etc. 2 mégaoctets ne représentent pas 2 000 000 octets. .

UPDATE Commenter a souligné qu'il existait des conditions spéciales pour les exposants numériques de 2: http://en.wikipedia.org/wiki/Mebibyte

Monsieur TA
la source
"2 mégaoctets ne représentent pas 2 000 000 octets." Demandez à n'importe quel fabricant de disque dur sur plateau tournant. (Pas le votant, d'ailleurs.)
un CVn
@ michaelkjorling c'est une question de programmation, pas d'éthique des affaires ou de marketing. Je suis d'accord sur les disques durs, mais c'est un sujet différent. Et a propos des votes négatifs!
M. TA
1
En fait, 2 mégaoctets correspondent à 2 000 000 octets. 2 Mebibytes est 2 097 152 octets. Voir en.wikipedia.org/wiki/Mebibyte
vy32
@ vy32 merci, jamais entendu parler de cela auparavant. Mettra à jour ma réponse pour refléter cela.
M. TA
@ Mr.TA, pas de problème! Nous travaillons fort pour que l'informatique soit conforme aux unités SI! Joindre le club.
vy32