Ist es in Sprachen, in denen Unterstriche in ganzzahligen Konstanten nicht zulässig sind, empfehlenswert, eine Konstante für 1 Milliarde zu erstellen?


39

Ist es in Sprachen, die keine Unterstriche in ganzzahligen Literalen zulassen , eine gute Idee, eine Konstante für 1 Milliarde zu erstellen? zB in C ++:

size_t ONE_BILLION = 1000000000;

Sicherlich sollten wir keine Konstanten für kleine Zahlen wie 100 erstellen. Bei 9 Nullen ist es jedoch wahrscheinlich einfach, eine Null wegzulassen oder eine zusätzliche Eins im Code wie folgt hinzuzufügen:

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

24
Ich hoffe, jeder hier stimmt für NEIN . Auf diese Weise überweist meine Bank vielleicht eines Tages eine Milliarde Dollar auf mein Konto, weil ein Programmierer keine Konstante verwendet und eine Null falsch platziert hat! :)
Reactgular

43
Warum nicht Konstanten für kleine Zahlen erstellen? Was bedeutet 100? Es ist eine magische Zahl, es sei denn, es gibt einen Zusammenhang.
Allan

4
@MathewFoscarini Im Allgemeinen können Fehler in beide Richtungen gehen. Aber wenn es um Ihre Bank geht, werden Fehler immer gegen Sie gehen.
Emory

23
Überlegen Sie 1e9, ob Sie schreiben möchten 10^9oder 1_000_000_000ob die von Ihnen verwendete Sprache dies unterstützt.
Hammar

Antworten:


33

Die meisten Sprachen haben eine Art Exponentialnotation. Eine Million ist 1e6, (was 1 mal 10 hoch 6 bedeutet). Dies löst das Problem im Grunde noch besser als die meisten Vorschläge hier.

In vielen C-ähnlichen Sprachen definiert die wissenschaftliche Notation jedoch einen Gleitkommatyp , was unglücklich ist, wenn Sie wirklich ein int benötigen. Sie können diese Konstante jedoch leicht tippen, um implizite Konvertierungen in Ihrem Formular zu vermeiden.

n / int(1e9) würde durch eine Milliarde teilen.

In Ihrem Beispiel, das sich mit physikalischen Größen (Zeit in Nanosekunden) befasst, würde ich mich generell fragen, ob eine Ganzzahl der richtige Typ ist. Tatsächlich ist ein Gleitkomma doublemöglicherweise besser geeignet, um mit messbaren Größen umzugehen (obwohl es natürlich Fälle gibt, in denen Sie a vorziehen würden long long).


6
Ich denke, die NANOSECONDS_IN_ONE_SECOND-Lösung ist viel klarer und ordentlicher
Thomas Bonini

1
Die Frage betraf ganzzahlige Liberale, und ich schlage vor, die wissenschaftliche Notation zu verwenden. Ob dies an Ort und Stelle oder durch Definieren einer Konstante geschehen soll, ist eine Frage der Codestrukturierung, die in der Frage nicht gefragt wurde. Wenn Sie eine Konstante definieren, die eine begrenzte Abstraktion hinzufügt, würde ich eine Konvertierungsfunktion / ein Makro schreiben, um eine bessere Abstraktion zu erzielen
wirrbel

1
Würde das Umwandeln eines sehr großen Double in ein Int nicht die typischen Rundungsdifferenzprobleme von Gleitkommazahlen riskieren?
Philipp

Bei Integer-Typen mit normaler Genauigkeit sollte dies kein Problem sein, solange Sie zum Konvertieren einen Gleitkommawert mit doppelter Genauigkeit verwenden. Sie haben Recht, wenn Sie Werte aus dem long longBereich verwenden.
Wirrbel

145

Erstellen Sie stattdessen eine mit dem Namen NANOSECONDS_IN_ONE_SECOND als das, was sie darstellt.

Oder ein kürzerer, besserer Name, wenn Sie sich einen vorstellen können.


58
Ich würde sagen, Nanoseconds_Per_Secondaber dies ist meiner Meinung nach die richtige Antwort.
KChaloux

8
@Mathew Ich verstehe deinen Standpunkt nicht. Es ist nichts Falsches daran, Millimeter pro Meter zu sagen. Sie können bedeuten, dass es redundant ist, in dieser Nanosekunde bedeutet dies eine Milliarde Sekundenbruchteile, aber es ist nichts Falsches daran, es erneut anzugeben. Es ist so, als würde man 1 + 1 = 2 sagen. "X pro y" ist immer noch sinnvoller, wenn x und y disjunkt sind, z. B. "Einheiten pro halbes Dutzend" oder "Nanosekunden pro Millisekunde"
Mark Canlas

7
@MathewFoscarini Eigentlich nein, in diesem Zusammenhang ist es nicht. Wenn NANOSECONDSja , ist eine Konstante namens bedeutungslos, da Sie nicht sagen können, worauf sie angewendet werden soll. Ebenso NANOSECONDS_PER_MICROSECONDist eine ähnliche gültige Konstante sinnvoll.
Izkata

5
@MathewFoscarini, "Millimeter pro Meter" ist eine Möglichkeit, die Einheit bei der Umrechnung zu entfernen, um den Rohwert zu erhalten. 1mm/1m = 1000, Das ist genau der Punkt , von dem, was hier getan wird.
zzzzBov

11
Warum so viel tippen? NS_PER_SECsollte jedem klar sein, der es mit Nanosekunden zu tun haben sollte.
Rex Kerr

67

Konstanten sollen Zahlen einen Sinn geben. Es gibt keine zusätzliche Bedeutung in ONE_BILLIONzu 1000000000. Tatsächlich ist es verwirrender, denn in verschiedenen natürlichen Sprachen bedeutet eine Milliarde etwas anderes (entweder eine Milliarde oder eine Million)! Wenn Sie es kürzer schreiben möchten, gibt es eine gute Chance, dass Ihre Programmiersprache die Verwendung der wissenschaftlichen Notation ermöglicht, dh 1e9. Ansonsten stimme ich @JohnB zu, dass diese Zahl wirklich die Anzahl der Nanosekunden pro Sekunde bedeutet.


9
Gut zu wissen, dass Milliarden in verschiedenen Sprachen eine unterschiedliche Anzahl von Nullen bedeuten.
Frozenkoi

3
würde vorschlagen, reguläre Sprachen in natürliche Sprachen zu ändern. regelmäßig bedeutet etwas anderes ...
jk.

Unterschiedliche Interpretationen von "Milliarden" in Sprachen sind so ein guter Punkt! Warum kann ich Ihre Antwort nicht zweimal positiv bewerten?
DSF

3
Sie brauchen keine anderen Sprachen. Sie brauchen nicht einmal verschiedene Länder. Im britischen Englisch bedeutet "Milliarde" etwas anderes vor und nach 1974 in der offiziellen Kommunikation (Massenmedien und Regierung), und beide Verwendungen existieren immer noch.
Jörg W Mittag

1
" Es gibt in ONE_BILLION keine zusätzliche Bedeutung für 10000000000.. Ich bin anderer Meinung. (Hinweis: Ich habe Sie absichtlich falsch zitiert und eine weitere Null hinzugefügt; hätte es bemerkt, wenn ich es nicht erwähnt hätte?)
Keith Thompson

27

Für ein oder zwei Verwendungen würde ich die Konvention verwenden:

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

Es ist vollkommen selbsterklärend, wird zu einer Konstanten kompiliert und es ist schwer zu vermasseln.

Es ist auch sehr nützlich in Fällen wie:

var Time = 24 * 60 * 60;

Wo es leicht zu sehen ist, reden wir über einen Tag in Sekunden.


Das ist was ich normalerweise mache. Es hat auch den Vorteil, dass ich nicht vergesse, dass ich gestern NANOSECONDS_IN_ONE_SECOND und heute NANOSECONDS_PER_SECOND definiert habe. Und morgen vielleicht EINE AMERIKANISCHE MILLIARD.
Thomas Padron-McCarthy

Sicher ist 'SecondsInOneDay = 24 * 60 * 60' noch einfacher?
JBRWilkinson

@JBRWilkinson sicher, mein anfängliches Snippet benutzte eine Klasse instance.Time = ..., aber dann habe ich es niedergeschlagen ...
Sklivvz

3
In C oder C ++ (1000 * 1000 * 1000)ist es vom Typ int, der nur 16 Bit haben muss, damit er überlaufen kann. Sie können schreiben (1000L * 1000L * 1000L), um das zu vermeiden.
Keith Thompson

Ich mache das oft. Es funktioniert sehr gut.
vy32

10

Die Länge des Werts bestimmt nicht, ob eine Konstante benötigt wird oder nicht.

Sie verwenden Konstanten, um magische Zahlen zu vermeiden, und nicht, um das Tippen zu vermeiden.

Zum Beispiel sind dies vollkommen gültige Konstanten:

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;

Verwenden:

public static final int NANOSECS_PER_SECOND = 1000000000;

(Codebeispiele sind in Java und werden in Ihre Lieblingssprache übersetzt.)


3
+1 Benannte Nummern sind fast nutzlos. Der Zweck von Konstanten besteht darin, diesen Zahlen einen Sinn zu geben. Was repräsentieren sie? Was zählen sie, was begrenzen sie oder was nennen sie den Koeffizienten? Nicht was ist der Wert der Zählung.
JustinC


2
Das sind schreckliche Beispiele für gültige Konstanten. Sie sollten Aufzählungen sein, außer sie wurden vor Aufzählungen erstellt.
Christoffer Hammarström

@ ChristofferHammarström Sie wurden tatsächlich vor Aufzählungen erstellt. Sie sind Teil der ResultSet-Klasse im SQL-Paket des Java SDK.
Tulains Córdova

2
@ ChristofferHammarström Sie sind schlecht, weil wir jetzt Aufzählungen haben, aber nicht dafür, dass wir nicht bedenklich sind. Enum gab es nicht, als diese Klassen erstellt wurden, und um zwischen sich gegenseitig ausschließenden Optionen wie FETCH_FORWARD und FETCH_REVERSE zu unterscheiden, geben Sie ihnen einen anderen Wert. Der Wert spielt keine Rolle, nur die Tatsache, dass sie unterschiedlich sind.
Tulains Córdova

8

Eine amerikanische oder europäische Milliarde?

(oder in technischer Hinsicht eine Milliarde im kurzen oder im langen Maßstab - eine ist 1000 Millionen, die andere ist eine Million Millionen).

In Anbetracht dieser Verwirrung würde ich ja sagen - es ist sinnvoll, es einmal zu definieren und dabei zu bleiben. Dies gilt auch für alle Konstanten, bei denen Sie sich auf die Definition einigen müssen - definieren Sie es einmal.


17
"Eine amerikanische oder europäische Milliarde?" - "Was? Das weiß ich nicht! Ahhhhh !!!!"
Tesserex

Zumindest in Großbritannien haben wir die 1e9 Milliarden längst übernommen.
Jack Aidley

1
@Tesserex - du musst diese Dinge wissen, wenn du ein König bist, weißt du?
gbjbaanb

5

Gründe, nicht zu

Erstens gibt es hier einen Grund, keine Unterstriche zu schreiben oder einen Trick zu verwenden, um dies zu simulieren: Es erschwert das Auffinden der Konstanten im Code. Angenommen, ein Programm weist irgendwo in seiner Operation einen fest codierten Wert von 1500000 für einen Parameter auf. Ich möchte wissen, wo im Quellcode des Programms dies tatsächlich vorkommt, also greife ich nach dem Code 1500000und finde nichts. Warum? Könnte es hexadezimal sein (aber warum für eine solche runde Dezimalzahl). Mir ist nicht bekannt, dass die Konstante tatsächlich so geschrieben ist 1_500_000. Ich brauchte den Regex 1_?500_?000.

Leitfiguren im Kommentar

Nur weil eine Art von visueller Hilfe nicht verfügbar ist oder wir sie aus dem oben genannten Grund nicht verwenden möchten, bedeutet dies nicht, dass wir die beiden Dimensionen der Textdatei nicht nutzen können, um eine alternative visuelle Hilfe zu erstellen:

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

Damit können wir uns leicht davon überzeugen, dass es drei Gruppen von drei Nullen gibt. Trotzdem können wir den Quellcode durchsuchen 1000000000und finden.

Syntax-Färbung

Ein Texteditor mit programmierbarer Syntaxfärbung kann zur besseren Lesbarkeit in numerischen Konstanten mit alternierenden Farben in Farbgruppen eingeteilt werden. Wir müssen nichts im Code tun.

Vorverarbeitung: C, C ++, Ziel C

Wenn wir nun wirklich Kommas zwischen Ziffern wollen, können wir in C und C ++ eine Vorverarbeitung verwenden:

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

Funktioniert für Zahlen wie TH(1,234,567,890).

Ein TH-ähnliches Makro kann auch mit Token-Einfügen anstelle von Arithmetik arbeiten. Im C-Präprozessor kann der Binäroperator ##("Token Paste") in einem Makrotext verwendet werden, um zwei Operanden zu einem einzigen Token zusammenzufügen. Einer oder beide Operanden können Makroargumente sein. Der Nachteil hier (was ein Risiko für uns darstellt) ist, dass das Verhalten undefiniert ist, wenn die resultierende Verkettung kein gültiges Token ist.

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

Jetzt

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

C-Programme, die Bezeichner zusammenfügen und die Ergebnisse verwenden, um globale Variablen und Funktionen zu benennen, existieren und sind schrecklich zu bearbeiten, da sie für Tools wie GNU-ID-Utils und -Ctags undurchlässig sind.


2
+1 für einen der besten Missbräuche des Präprozessors, den ich gesehen habe. Ich würde trotzdem mit NSEC_PER_SEC oder so in Produktion gehen.
Victor

Fast -1 für den Missbrauch des Präprozessors :)
ein Lebenslauf

3

Ja, das klingt nach einer vernünftigen Idee. Off-by-One-DIGIT-Fehler sind noch schlimmer als die berüchtigten Off-by-One-Fehler. Es kann jedoch Verwirrung stiften, wenn andere Personen (einschließlich Ihres zukünftigen Selbst) den Code lesen.

Ein erklärenderer Name wie NANOSEC_PER_SEC scheint gut zu sein, da er Klarheit darüber verschafft, wo er für die Zeit verwendet wird. Die Verwendung in anderen Kontexten als der Zeit ist jedoch nicht sinnvoll und es wäre unpraktisch, für jede Situation eine separate 1.000.000.000 zu erstellen.

Was Sie wirklich tun möchten, so albern es zunächst aussieht, ist "Teilung über Sekunde". Dadurch bleibt NANO_PER erhalten, das nicht nur sprachunabhängig ist (10 ^ 9 in Amerika und Europa), sondern auch situationsunabhängig (keine Beschränkung der Einheiten), und es ist einfach zu tippen und zu lesen.


Dieser Beitrag ist ziemlich schwer zu lesen (Textwand). Hätten Sie etwas dagegen bearbeiten sie in eine bessere Form ing?
gnat

3

Im Allgemeinen ist es eine schlechte Idee, skalare Konstanten für Einheitenumrechnungen zu verwenden, und wenn Sie Konstanten für solche Dinge erstellen, führen Sie die Umrechnung an viel zu vielen Stellen durch.

Wenn Sie eine Größe von einer Einheit (z. B. 10 Sekunden) haben und in eine andere Einheit (z. B. Nanosekunden) umrechnen möchten; Dies ist genau der Zeitpunkt, um das Typensystem Ihrer Sprache zu verwenden und sicherzustellen, dass die Einheiten tatsächlich so skaliert werden, wie Sie es beabsichtigen.

Machen Sie Ihre Funktion einen nehmen NanosecondsParameter und liefern Umwandlung Betreiber und / oder Konstrukteuren in dieser Klasse für Seconds, Minutesoder was-haben-Sie. Dies ist, wo Ihre const intoder #defineoder 1e9in anderen Antworten gesehen gehört.

Dadurch wird vermieden, dass Variablen mehrdeutiger Einheiten in Ihrem Code schweben. und verhindert ganze Schwaden von Fehlern, bei denen die falsche Multiplikation / Division angewendet wurde oder bereits angewendet wurde oder die Menge tatsächlich Abstand statt Zeit war, oder ...

In solchen Klassen empfiehlt es sich außerdem, eine Konstruktion aus einfachem Skalarsprivate zu erstellen und ein statisches "MakeSeconds (int)" oder ähnliches zu verwenden, um die unbeholfene Verwendung undurchsichtiger Zahlen zu unterbinden.

In C ++ können Sie Boost.Chrono genauer untersuchen .


1
+ Verwenden Sie mindestens einen gebräuchlichen Typ mit einem Skalierungs- oder Versatzfaktor von einer Basis, ähnlich wie bei der häufig fehlerhaften Zeitzone.
JustinC

1

Ich persönlich halte es nicht für eine gute Praxis, eine Konstante zu erstellen, es sei denn, es muss eine Konstante sein. Wenn es sich an mehreren Stellen befindet und oben in der Datei definiert ist, um es zu ändern oder zu testen, ist es absolut nützlich.

Wenn es nur weil es umständlich zu tippen ist? dann nein.

Persönlich, wenn ich den Code einer anderen Person habe, für den eine Konstante definiert ist, halte ich dies im Allgemeinen für einen wichtigen Aspekt des Codes. ZB tcp Keep Alive Timer, maximal zulässige Anzahl von Verbindungen. Wenn ich es debuggen müsste, würde ich wahrscheinlich viel unnötige Aufmerksamkeit darauf richten, um herauszufinden, warum / wo es verwendet wird.


Ich verstehe den Witz, aber wenn Bankprogrammierer für jede Zahl eine Konstante erstellen müssten, die Sie übertragen könnten, wäre die Software gigantisch, unüberschaubar und langsam. Ich konnte mir nur vorstellen, wie das wäre. Stellen Sie sich vor, es würde 3 Arbeitstage dauern, um Geld zu überweisen ... OH MEIN GOTT, DAS IST ES !!!
Simon McLoughlin

Meine Bank benötigt 3 Tage, um Geld zu überweisen :(
Reactgular

1
@ MathewFoscarini Banker verwenden Excel, sie brauchen keine Programmierer;)
Mateusz

@Simon Abhängig von Sprache und Compiler sollten Konstanten im Code optimiert werden, was nur einen geringen Aufwand bedeutet. Ich verstehe Ihren Standpunkt, aber Konstanten können überall dort verwendet werden, wo die Lesbarkeit des Codes durch die Verwendung eines Namens anstelle einer magischen Zahl verbessert wird.
Steven

Umständlich zu lesen ist viel mehr ein Problem als umständlich zu tippen.
Alb

0

Wenn Sie darüber nachdenken, warum Sie in Ihrem Fragentitel "1 Milliarde" anstelle von "1000000000" geschrieben haben, werden Sie feststellen, warum die Antwort "Ja" lautet.


0

Erstellen Sie keine Konstante für Ihre großen Literale. Für jedes dieser Wörter braucht man eine Konstante, was meiner Meinung nach ein Witz ist. Wenn Sie Ihre Literale unbedingt ohne die Hilfe von Syntaxhervorhebungen klarer machen müssen, können Sie (obwohl ich es nicht tun würde) Funktionen oder Makros erstellen, um Ihr Leben "einfacher" zu machen:

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

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

0

Ich würde das machen:

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

oder

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

In Bezug auf die Anzahl der Nanosekunden pro Sekunde: Nano ist die "Inverse" von Giga.

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

Beachten Sie das "Sci" - für wissenschaftliche Zwecke sind die Bedeutungen von Kilo, Mega, Giga usw. unterschiedlich: 1024 (2 ^ 10), 1024 * 1024 (2 ^ 20) usw. 2 Megabyte sind nicht 2.000.000 Bytes .

UPDATE Commenter wies darauf hin, dass für digitale Exponenten von 2 spezielle Begriffe existieren: http://en.wikipedia.org/wiki/Mebibyte


"2 Megabyte sind nicht 2.000.000 Bytes." Wenden Sie sich an den Hersteller der gewünschten Spinning-Platter-Festplatte. (Übrigens nicht der Abwähler)
ein Lebenslauf

@michaelkjorling das ist eine programmierfrage, keine wirtschaftsethische oder marketingfrage. Ich stimme in Bezug auf Festplatten zu, aber das ist ein anderes Thema. Und autsch über die Abwahlen!
Mr. TA

1
Tatsächlich sind 2 Megabyte 2.000.000 Bytes. 2 Mebibytes sind 2.097.152 Bytes. Siehe en.wikipedia.org/wiki/Mebibyte
vy32

@ vy32 danke, habe noch nie davon gehört. Ich werde meine Antwort aktualisieren, um das wiederzugeben.
Herr TA

@ Mr.TA, kein Problem! Wir arbeiten hart daran, die Informatik mit den SI-Einheiten in Einklang zu bringen! Tritt in den Klub ein.
Vy32
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.