Zero come costante?


15

Mi sono imbattuto recentemente in questo linguaggio di programmazione:

const float Zero = 0.0;

che viene quindi utilizzato nei confronti:

if (x > Zero) {..}

Qualcuno può spiegare se questo è davvero più efficiente, leggibile o mantenibile di:

if (x > 0.0) {..}

NOTA: posso pensare ad altri motivi per definire questa costante, mi sto solo chiedendo quale sia il suo utilizzo in questo contesto.


31
Gli sviluppatori stanno pianificando di trasferire il codice in un universo in cui le leggi della matematica sono diverse?
Vaughandroid,

6
Scherzi a parte, non riesco a pensare a una sola buona ragione per questo. Le uniche spiegazioni che posso trovare sono standard di codifica troppo zelanti, o alcuni sviluppatori che hanno sentito "i numeri magici sono cattivi" ma non capiscono perché (o cosa costituirebbe un numero magico) ...
vaughandroid

@Baqueta -Un universo alternativo? Penso che abbiano già vissuto lì! Per quanto riguarda i numeri magici, sono d'accordo, tuttavia uso la regola empirica che tutto tranne 0 e 1 dovrebbe essere reso costante.
NWS,

1
Se xha tipo float, x > 0.0forza la promozione a double, che potrebbe essere meno efficiente. Questo non è un buon motivo per usare una costante con nome, solo per assicurarsi che le costanti abbiano il tipo corretto (es 0f. float(0)O decltype(x)(0)).
Mike Seymour,

1
@JoSo: per essere onesti, il tipo di 13.37non lo è float, lo è double. Quindi, se lo volevi float, è concepibile che il tuo tutor fosse corretto. In alcuni contesti (ad es. Assegnazione a un float) 13.37verrà implicitamente convertito nel valore floatdesiderato e in altri contesti (ad es. Deduzione del tipo di modello) non lo sarà, mentre static const floatinizia sempre come tipo desiderato. Quindi, più sicuro per i tipi. Intendiamoci, così sarebbe 13.37f! Esistono altri motivi per evitare la macro oltre alla "sicurezza dei tipi", quindi è altrettanto probabile che il tutor ti dia una discussione scadente.
Steve Jessop,

Risposte:


29

I possibili motivi sono la memorizzazione nella cache, la denominazione o il tipo di forzatura

Memorizzazione nella cache (non applicabile)

Vuoi evitare il costo di creazione di un oggetto durante l'atto di confronto. In Java un esempio sarebbe

BigDecimal zero = new BigDecimal ("0.0");

questo comporta un processo di creazione abbastanza pesante ed è meglio servito usando il metodo statico fornito:

BigDecimal zero = BigDecimal.ZERO;

Ciò consente confronti senza incorrere in costi di creazione ripetuti poiché BigDecimal è pre-memorizzato nella cache da JVM durante l'inizializzazione.

Nel caso di ciò che hai descritto, una primitiva sta eseguendo lo stesso lavoro. Ciò è in gran parte ridondante in termini di memorizzazione nella cache e prestazioni.

Denominazione (improbabile)

Lo sviluppatore originale sta tentando di fornire una convenzione di denominazione uniforme per valori comuni in tutto il sistema. Questo ha qualche merito, specialmente con valori non comuni ma qualcosa di basilare come zero ne vale la pena solo nel caso della cache precedente.

Tipo di forzatura (molto probabilmente)

Lo sviluppatore originale sta tentando di forzare un particolare tipo di primitiva per garantire che i confronti vengano espressi sul tipo corretto e possibilmente su una scala particolare (numero di cifre decimali). Questo è OK, ma il semplice nome "zero" è probabilmente un dettaglio insufficiente per questo caso d'uso con ZERO_1DP che è un'espressione più appropriata dell'intento.


2
+1 per forzare il tipo. Aggiungerò che in linguaggi come C ++ che consentono il sovraccarico dell'operatore, la definizione di una costante e l'uso di typedefmanterrebbero il tipo della variabile esattamente in un posto e consentirebbero di cambiarlo senza dover modificare il codice.
Blrfl,

3
Tipo Forzare è più probabile non è quello che stavano cercando per, ma questa è la migliore spiegazione del motivo per cui si potrebbe fare!
NWS,

7
Per forzare il tipo, probabilmente preferirei semplicemente usare 0.0f.
Svish,

Il tipo di forzatura può talvolta essere utile in vb.net, dove l'esecuzione di operatori bit a bit su byte produce un risultato byte. Dire byteVar1 = byteVar2 Or CB128sembra un po 'più bello di byteVar1 = byteVar2 Or CByte(128). Ovviamente, avere un suffisso numerico adeguato per i byte sarebbe ancora meglio. Dal momento che C # promuove gli operandi di bit per bit agli operatori intanche quando il risultato sarebbe garantito per adattarsi a a byte, il problema non è così rilevante lì.
supercat

Non sono sicuro di avere il nome costante come Zero per '0', ma a volte aiuta nella leggibilità del codice; per esempio, avere questa costante per zero - "ROOT_TYPE_ID = 0" aiuterà a scrivere un'istruzione come if (id! = ROOT_TYPE_ID) {..}
Tech Junkie

6

È a causa del "fastidio degli utensili"

Un possibile motivo che non vedo elencato qui è perché molti strumenti di qualità segnalano l'uso di numeri magici . Spesso è una cattiva pratica avere numeri magici gettati in un algoritmo senza renderli chiaramente visibili per il cambiamento in seguito, specialmente se sono duplicati in più punti del codice.

Quindi, mentre questi strumenti hanno ragione a segnalare tali problemi, spesso generano falsi positivi per situazioni in cui questi valori sono innocui e molto probabilmente sono statici o semplicemente valori di inizializzazione.

E quando ciò accade, a volte devi affrontare la scelta di:

  • contrassegnandoli come falsi positivi, se lo strumento lo consente (di solito con un commento appositamente formattato, che è fastidioso per le persone che NON utilizzano lo strumento)
  • o estrarre questi valori nelle costanti, che contino o meno.

Informazioni sulle prestazioni

Dipende dal linguaggio immagino, ma questo è abbastanza comune in Java e non ha alcun impatto sulle prestazioni, poiché i valori sono integrati al momento della compilazione se sono costanti reali static final. Non avrebbe alcun impatto in C o C ++ se vengono dichiarate come costanti o anche come macro pre-processore.


5

Questo potrebbe avere senso poiché definisce esplicitamente Zerodi essere di tipo float.

Almeno in C e C ++ il valore 0.0è di tipo double, mentre l'equivalente floatè 0.0f. Quindi assumere il xconfronto con è sempre anche un modo di floatdire

x > 0.0

mentre in realtà promuovono xper doubleabbinare il tipo di ciò 0.0che potrebbe portare a problemi (con test di uguaglianza in particolare). Il confronto senza conversione sarebbe ovviamente

x > 0.0f

che fa lo stesso di

float Zero = 0.0; // double 0.0 converted to float  
x > Zero

Tuttavia, penso che sarebbe molto più utile abilitare gli avvisi di conversioni nel compilatore invece di far scrivere codice scomodo agli utenti.


1

Prima di tutto, qui zero è definito come float, non int. Naturalmente, questo non influisce su nulla nel confronto, ma in altri casi quando viene utilizzata questa costante, potrebbe fare la differenza.

Non vedo altro motivo per cui qui Zerosia dichiarata costante. È solo un po 'di stile di codifica ed è meglio seguire lo stile se viene utilizzato ovunque in quel determinato programma.


1

È quasi certamente altrettanto efficiente durante l'esecuzione (a meno che il compilatore non sia molto primitivo) e leggermente meno efficiente durante la compilazione.

Sul fatto che sia più leggibile di x > 0... ricorda che ci sono persone che onestamente, sinceramente, pensano che COBOL sia stata una grande idea e un piacere lavorare con - e poi ci sono persone che pensano esattamente lo stesso di C. (Rumor ha se esistono persino alcuni programmatori con la stessa opinione su C ++!) In altre parole, non otterrai un accordo generale su questo punto e probabilmente non vale la pena litigare.


0

[è] questo è davvero più efficiente, leggibile o mantenibile di:

if (x > 0.0) {..}

Se stavi scrivendo un codice generico (cioè non specifico del tipo), molto probabilmente. Una zero()funzione può essere applicata a qualsiasi tipo algebrico o qualsiasi tipo che sia un'aggiunta di gruppo. Potrebbe essere un numero intero, potrebbe essere un valore in virgola mobile, potrebbe anche essere una funzione se la tua variabile è, diciamo, essa stessa una funzione all'interno di uno spazio lineare (ad esempio x è una funzione lineare della forma z -> a_x * z + b_x) e quindi zero()fornisce alla funzione aeb entrambi zero()del tipo sottostante.

Quindi ci si aspetterebbe un simile codice, diciamo, forse in C ++ (sebbene zero()AFAIK non sia molto comune), o in Julia e forse in altre lingue.

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.