In lingue che non consentono il carattere di sottolineatura in costanti intere, è buona norma creare una costante per 1 miliardo?


39

In lingue che non consentono la sottolineatura in letterali interi , è una buona idea creare una costante per 1 miliardo? ad es. in C ++:

size_t ONE_BILLION = 1000000000;

Certamente, non dovremmo creare costanti per piccoli numeri come 100. Ma con 9 zeri, è probabilmente facile lasciare uno zero o aggiungerne uno in più in questo modo:

tv_sec = timeInNanosec / 1000000000;
tv_nsec = timeInNanosec % 1000000000;

24
Spero che tutti qui votino NO . In questo modo, forse un giorno la mia banca trasferirà un miliardo di dollari sul mio conto perché un programmatore non ha utilizzato una costante e ha posto uno zero fuori luogo! :)
Reactgular

43
Perché non creare costanti per piccoli numeri? Cosa significa 100? A meno che non ci sia un certo contesto, è un numero magico.
Allan,

4
@MathewFoscarini In generale, gli errori possono andare in entrambi i modi. Ma quando si tratta della tua banca, gli errori andranno sempre contro di te.
emory

23
Non crei 1e9, 10^9o 1_000_000_000se la lingua che si sta utilizzando lo supporta.
Hammar,

Risposte:


33

La maggior parte delle lingue presenta una sorta di notazione esponenziale. Un milione è 1e6, (che significa 1 volte 10 alla potenza di 6). Questo sostanzialmente risolve il problema anche meglio della maggior parte delle proposizioni qui.

In molti linguaggi simili a C, la notazione scientifica sta tuttavia definendo un tipo a virgola mobile , il che è un peccato se hai davvero bisogno di un int. Tuttavia, puoi facilmente digitare il cast di quella costante per evitare conversioni implicite nel tuo formulare.

n / int(1e9) si dividerebbe per un miliardo.

Nel tuo esempio, affrontando le quantità fisiche (tempo in nanosecondi), mi chiedo generalmente se il numero intero sia il tipo giusto. In effetti un virgola mobile doublepotrebbe essere più adatto quando si tratta di quantità misurabili (anche se ci sono ovviamente casi in cui si preferisce a long long).


6
Penso che la soluzione NANOSECONDS_IN_ONE_SECOND sia molto più chiara e ordinata
Thomas Bonini,

1
La domanda riguardava i liberali interi e propongo di usare la notazione scientifica. Se farlo sul posto o definendo una costante è un problema di strutturazione del codice che non è stato richiesto nella domanda. Definendo una costante si aggiunge un'astrazione limitata, scriverei una funzione di conversione / macro per ottenere una migliore astrazione
wirrbel,

1
lanciare un double molto grande in un int non rischierebbe i tipici problemi di differenza di arrotondamento dei numeri in virgola mobile?
Philipp,

con i normali numeri interi di precisione questo non dovrebbe essere un problema purché si usi un float a doppia precisione per la conversione. hai ragione quando usi i valori long longdell'intervallo.
Wirrbel,

145

Creane uno chiamato NANOSECONDS_IN_ONE_SECOND invece come quello che rappresenta.

O un nome più breve e migliore se riesci a pensare a uno.


58
Direi che Nanoseconds_Per_Secondquesta è, a mio avviso, la risposta corretta.
KChaloux,

8
@Mathew non capisco il tuo punto. Non c'è niente di sbagliato nel dire millimetri per metro. Potresti insinuare che è ridondante, in quel nanosecondo SIGNIFICA un miliardo di frazioni di secondo, ma non c'è nulla di sbagliato nel dichiararlo di nuovo. È come dire 1 + 1 = 2. "x per y" continua ad avere più senso quando xey sono disgiunti, come "unità per mezza dozzina" o "nanosecondi per millisecondo"
Mark Canlas

7
@MathewFoscarini In realtà no, in questo contesto non lo è. Se lo fosse, una costante denominata non ha NANOSECONDSsenso in quanto non si può dire a cosa dovrebbe applicarsi. Allo stesso modo, NANOSECONDS_PER_MICROSECONDè una costante valida simile che ha senso.
Izkata,

5
@MathewFoscarini, "millimetri per metro" è un modo per rimuovere l'unità dalla conversione per ottenere il valore grezzo. 1mm/1m = 1000, che è esattamente il punto di ciò che viene fatto qui.
zzzzBov,

11
Perché scrivere così tanto? NS_PER_SECdovrebbe essere ovvio per chiunque dovrebbe avere a che fare con nanosecondi.
Rex Kerr,

67

Le costanti hanno lo scopo di dare significato ai numeri. Non c'è alcun significato ulteriore ONE_BILLIONa 1000000000. In realtà, lo rende più confuso, perché in diversi linguaggi naturali, un miliardo significa qualcosa di diverso (mille milioni o un milione di milioni)! Se vuoi scriverlo più breve, ci sono buone probabilità che il tuo linguaggio di programmazione consenta l'uso della notazione scientifica, ad es 1e9. Altrimenti, sono d'accordo con @JohnB, che questo numero indica davvero il numero di nanosecondi in un secondo, quindi chiamatelo così.


9
È bene indicare che miliardi in lingue diverse significano quantità diverse di zeri.
frozenkoi,

3
suggerirei di cambiare le lingue normali in lingue naturali. regolare significa qualcos'altro ...
jk.

Diverse interpretazioni di "miliardi" in lingue un buon punto! Perché non posso votare due volte la tua risposta!
DSF,

3
Non hai bisogno di lingue diverse. Non hai nemmeno bisogno di paesi diversi. In inglese britannico, "miliardi" significa qualcosa di diverso prima e dopo il 1974 nelle comunicazioni ufficiali (mass media e governo), ed esistono ancora entrambi gli usi.
Jörg W Mittag,

1
" Non c'è alcun significato aggiuntivo in ONE_BILLION a 10000000000 .. Non sono d'accordo. (Suggerimento: ti ho deliberatamente citato e aggiunto un altro zero; avresti notato se non lo avessi menzionato?)
Keith Thompson

27

Per uno o due usi, userei la convenzione:

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

È perfettamente autoesplicativo, viene compilato in una costante ed è difficile sbagliare.

Inoltre, è molto utile in casi come:

var Time = 24 * 60 * 60;

dove è facile vedere, stiamo parlando di un giorno in pochi secondi.


Questo è quello che faccio di solito. Ha anche il vantaggio di non dimenticare che ieri ho definito NANOSECONDS_IN_ONE_SECOND e oggi NANOSECONDS_PER_SECOND. E forse ONE_AMERICAN_BILLION domani.
Thomas Padron-McCarthy,

Sicuramente 'SecondsInOneDay = 24 * 60 * 60' è ancora più facile?
JBR Wilkinson,

@JBRWilkinson certo, il mio frammento iniziale usava una classe instance.Time = ..., ma poi l'ho
smorzato

3
In C o C ++, (1000 * 1000 * 1000)è di tipo int, che deve essere solo di 16 bit, quindi può traboccare. Puoi scrivere (1000L * 1000L * 1000L)per evitarlo.
Keith Thompson,

Lo faccio molto. Funziona molto bene
vy32,

10

La lunghezza del valore non è ciò che definisce se è necessaria o meno una costante.

Usa le costanti per evitare numeri magici , non per scrivere.

Ad esempio queste sono costanti perfettamente valide:

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;

Uso:

public static final int NANOSECS_PER_SECOND = 1000000000;

(esempi di codice sono in Java, traduci nella tua lingua preferita)


3
+1 I numeri nominati sono quasi inutili. Lo scopo delle costanti è quello di dare significato a quei numeri. Cosa rappresentano? Che cosa stanno contando o limitando o coefficiente formalmente nominato? Non qual è il valore del conteggio.
Giustino


2
Questi sono terribili esempi di costanti valide. Avrebbero dovuto essere enumerazioni, tranne per il fatto che erano state create prima delle enumerazioni.
Christoffer Hammarström,

@ ChristofferHammarström Sono stati effettivamente creati prima degli enum, fanno parte della classe ResultSet, nel pacchetto SQL di Java SDK.
Tulains Córdova,

2
@ ChristofferHammarström Sono cattivi perché ora abbiamo enumerazioni, ma non per essere sconsiderati. Enum non esisteva al momento della creazione di queste classi e al fine di differenziare tra opzioni reciprocamente esclusive come FETCH_FORWARD e FETCH_REVERSE sta dando loro un valore diverso. Il valore non ha importanza, solo il fatto che sono diversi.
Tulains Córdova,

8

Un miliardo americano o europeo?

(o in termini tecnici, un miliardo in scala corta o lunga - uno è 1000 milioni, l'altro è un milione milioni).

Data questa confusione, allora direi di sì - ha senso definirlo una volta e mantenerlo, allo stesso modo si applica a qualsiasi costante su cui è necessario concordare la definizione - definirla una volta.


17
"Un miliardo americano o europeo?" - "Cosa? Non lo so! Ahhhhh !!!!"
Tesserex,

Nel Regno Unito, almeno, abbiamo da tempo adottato il 1e9 miliardi.
Jack Aidley

1
@Tesserex - bene, devi sapere queste cose quando sei un re, lo sai.
gbjbaanb,

5

Ragioni per non farlo

In primo luogo, ecco un motivo per non scrivere caratteri di sottolineatura o usare alcun trucco per simularlo: rende le costanti più difficili da trovare nel codice. Supponiamo che alcuni programmi mostrino, da qualche parte nel suo funzionamento, un valore hard-code 1500000 per alcuni parametri. Voglio sapere dove si verifica effettivamente nel codice sorgente del programma, quindi grep il codice 1500000e non trovo nulla. Perché? Potrebbe essere in esadecimali (ma perché per un numero decimale tondo). A mia insaputa, la costante è in realtà scritta come 1_500_000. Avevo bisogno di regex 1_?500_?000.

Personaggi guida nel commento

Solo perché un tipo di aiuto visivo non è disponibile o non desideriamo utilizzarlo per il motivo precedente, non significa che non possiamo sfruttare le due dimensioni del file di testo per creare un aiuto visivo alternativo:

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

Con questo possiamo facilmente convincerci che ci sono tre gruppi di tre zeri. Tuttavia, possiamo ancora grep per il codice sorgente 1000000000e trovarlo.

Sintassi da colorare

Un editor di testo con colorazione di sintassi programmabile può essere creato per colorare gruppi di cifre in costanti numeriche con colori alternati per una migliore leggibilità. Non dobbiamo fare nulla nel codice.

Preelaborazione: C, C ++, Obiettivo C

Ora, se vogliamo davvero alcune virgole tra le cifre, in C e C ++ possiamo usare un po 'di preelaborazione:

/* 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)

Funziona per numeri come TH(1,234,567,890).

Una macro simile a TH può anche funzionare con incollare token anziché con l'aritmetica. Nel preprocessore C, l' ##operatore binario ("token paste") può essere utilizzato in un corpo macro per incollare due operandi in un singolo token. Uno o entrambi gli operandi possono essere argomenti macro. Il rovescio della medaglia qui (creando un rischio per noi) è che se la catenazione risultante non è un token valido, il comportamento non è definito.

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

Adesso

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 */

Esistono programmi C che incollano identificatori e usano i risultati per nominare variabili e funzioni globali e sono terribili con cui lavorare perché sono impermeabili a strumenti come GNU id-utils e ctags.


2
+1 per uno dei migliori abusi del preprocessore che abbia mai visto. Andrei comunque con NSEC_PER_SEC o qualcosa in produzione, comunque.
Victor,

Quasi -1 per aver abusato del preprocessore :)
un CVn del

3

Sì, sembra un'idea ragionevole. Gli errori DIGIT off-by-one sono persino peggiori dei famigerati errori off-by-one. Tuttavia, può creare confusione per altre persone (incluso il tuo sé futuro) per leggere il codice.

Un nome più esplicativo come NANOSEC_PER_SEC sembra buono, in quanto aggiungerebbe chiarezza dove viene utilizzato per il tempo. Tuttavia, non ha senso utilizzare in contesti diversi dal tempo e non sarebbe pratico creare 1.000.000.000 separate per ogni situazione.

Quello che vuoi davvero fare, sciocco come sembra all'inizio, è "dividi in secondi". Questo lascia NANO_PER, che non è solo indipendente dalla lingua (10 ^ 9 in America ed Europa) ma anche indipendente dalla situazione (senza limitare le unità), ed è facile da scrivere e da leggere.


questo post è piuttosto difficile da leggere (wall of text). Ti dispiacerebbe modificarlo in una forma migliore?
moscerino del

3

In generale è una cattiva idea usare costanti scalari per conversioni di unità, e se ti ritrovi a creare costanti per tali cose, stai facendo conversioni in troppi posti.

Quando hai una quantità di un'unità (diciamo, 10 secondi) e vuoi convertirla in un'altra unità (ad es. Nanosecondi); questo è precisamente il momento di utilizzare il sistema di tipi della tua lingua per garantire che le unità siano effettivamente ridimensionate come previsto.

Fai la tua funzione di prendere un Nanosecondsparametro e fornire agli operatori di conversione e / o costruttori in tale ramo Seconds, Minuteso quello che-hanno-te. Questo è dove il vostro const into #defineo 1e9visto in altre risposte appartiene.

Questo evita di avere variabili di unità ambigue che fluttuano attorno al tuo codice; e impedisce intere strisce di bug da dove è stata applicata la moltiplicazione / divisione errata, o era già stata applicata, o la quantità era effettivamente distanza anziché tempo, o ...

Inoltre, in tali classi è bene rendere privata la costruzione da semplici scalari e usare un "MakeSeconds (int)" statico o simile per scoraggiare l'uso sciatto di numeri opachi.

Più precisamente al tuo esempio, in C ++ controlla Boost.Chrono .


1
+ Per lo meno, usa un tipo comune con un fattore di ridimensionamento o offset da una base, proprio come il fuso orario spesso diffamato.
Giustino

1

Personalmente non considero una buona pratica creare una costante a meno che non debba essere una costante. Se sarà in più punti e averlo definito nella parte superiore del file per modifiche / o test sarà utile, allora assolutamente.

Se è solo perché è scomodo da digitare? allora no.

Personalmente, se ottengo il codice di qualcun altro con una costante definita, in genere lo considero un aspetto importante del codice. Ad esempio tcp mantiene in vita i timer, è consentito il numero massimo di connessioni. Se dovessi eseguire il debug, probabilmente presterei molta attenzione non necessaria al tentativo di capire perché / dove viene utilizzato.


Ho capito la battuta ma se i programmatori di banche dovessero fare una costante per ogni numero che potresti trasferire il software sarebbe gigantesco, ingestibile e lento. Potevo solo immaginare come sarebbe stato, immagino che mi avrebbero detto che ci sarebbero voluti 3 giorni lavorativi per trasferire denaro a ... OH MIO DIO, TUTTO !!!
Simon McLoughlin,

La mia banca impiega 3 giorni per trasferire denaro :(
Reactgular

1
I banchieri di @MathewFoscarini usano Excel, non hanno bisogno di programmatori;)
Mateusz,

@Simon A seconda della lingua e del compilatore, le costanti dovrebbero essere ottimizzate nel codice, sostenendo un piccolo sovraccarico. Capisco il tuo punto, ma le costanti possono essere utilizzate ovunque usando un nome anziché un numero magico aiuterebbe la leggibilità del codice.
Steven,

Imbarazzante da leggere è molto più un problema che imbarazzante da scrivere.
Alb

0

Quando pensi al motivo per cui hai scritto "1 miliardo" anziché "1000000000" nel titolo della domanda, ti renderai conto del perché la risposta è sì.


0

Non creare una costante per i tuoi grandi letterali. Avresti bisogno di una costante per ognuno di questi letterali, che è (a mio avviso) uno scherzo completo. Se hai un disperato bisogno di rendere i tuoi letterali più chiari senza l'aiuto di cose come l'evidenziazione della sintassi, potresti (anche se non lo farei) creare funzioni o macro per rendere la tua vita "più facile":

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

int largeNumber1 = SPLIT3(123,456,789);
int largeNumber2 = 123456789;

0

Vorrei fare questo:

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

o

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

Per quanto riguarda il numero di nanosecondi al secondo: nano è "l'inverso" della giga.

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

Nota "Sci" - per scientifico, come nei computer, i significati di chilo, mega, giga ecc. Sono diversi: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20), ecc. 2 megabyte non sono 2.000.000 di byte .

AGGIORNAMENTO Il commentatore ha sottolineato che esistono termini speciali per esponenti digitali di 2: http://en.wikipedia.org/wiki/Mebibyte


"2 megabyte non sono 2.000.000 di byte." Chiedere a qualsiasi produttore di dischi rigidi del piatto rotante desiderato. (Non il downvoter, tra l'altro.)
un CVn,

@michaelkjorling questa è una domanda di programmazione, non di etica aziendale o di marketing. Sono d'accordo sui dischi rigidi, ma questo è un argomento diverso. E a proposito dei voti negativi!
Sig. TA,

1
In realtà, 2 Megabyte sono 2.000.000 di byte. 2 Mebibytes è 2.097.152 byte. Vedi en.wikipedia.org/wiki/Mebibyte
vy32 l'

@vy32 grazie, non ne avevo mai sentito parlare prima. Aggiornerò la mia risposta per riflettere questo.
Mr. TA,

@ Mr.TA, nessun problema! Stiamo lavorando duramente per rendere l'informatica conforme alle unità SI! Entra nel club.
vy32,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.