Bei einem kürzlich durchgeführten Projekt musste ich Kibibyte von Bytes in Kilobytes konvertieren . Der Code war einfach genug:
var kBval = byteVal / 1024;
Nachdem ich das geschrieben hatte, funktionierte der Rest der Funktion und ging weiter.
Aber später begann ich mich zu fragen, ob ich gerade eine magische Zahl in meinen Code eingebettet hatte . Ein Teil von mir sagt, es sei in Ordnung, weil die Zahl eine feste Konstante ist und leicht zu verstehen ist. Aber ein anderer Teil von mir denkt, dass es super klar gewesen wäre, wenn man es in eine definierte Konstante wie gewickelt hätte BYTES_PER_KBYTE
.
Sind Zahlen, die bekannte Konstanten sind, wirklich so magisch oder nicht?
Verwandte Fragen:
Wann ist eine Zahl eine magische Zahl? und Wird jede Zahl im Code als "magische Zahl" betrachtet? - sind ähnlich, aber es gibt viel umfassendere Fragen als das, was ich stelle. Meine Frage konzentriert sich auf bekannte konstante Zahlen, die in diesen Fragen nicht angesprochen werden.
Eliminierung magischer Zahlen: Wann ist es Zeit, "Nein" zu sagen? ist ebenfalls verwandt, konzentriert sich jedoch auf das Refactoring und nicht darauf, ob eine konstante Zahl eine magische Zahl ist oder nicht.
quelle
FOUR_HUNDRED_FOUR = 404
. Ich habe an einem anderen Projekt gearbeitet, bei dem sie gegen die Verwendung von Konstanten anstelle von Literalen kämpften. Sie hatten also Dutzende von Codezeilen, die so aussahenDATABASE = "database"
1024
, da Ihr Entwicklerteam sonst die ganze Zeit damit verbringt, sich darüber zu streiten, ob es sich um "Kilobyte" oder "Kibibyte" handelt.#define
KIBI
1024 ist,MEBI
als 1024 * 1024…ZERO=0, ONE=1, TWO=2
und wenn Programme in anderen Sprachen portiert werden (oder die Programmierer nicht Verhalten ändern , wenn ihre Sprachumschaltung) Sie es dort sehen werden , und Sie müssen beten , dass jemand es nie ändernONE=2
...Antworten:
Nicht alle magischen Zahlen sind gleich.
Ich denke in diesem Fall ist diese Konstante in Ordnung. Das Problem mit magischen Zahlen ist, wenn sie magisch sind, dh es ist unklar, woher sie stammen, warum der Wert so ist, wie er ist oder ob der Wert korrekt ist oder nicht.
1024 hinter BYTES_PER_KBYTE zu verstecken bedeutet auch, dass Sie nicht sofort sehen, ob es korrekt ist oder nicht.
Ich würde erwarten, dass jeder sofort weiß, warum der Wert 1024 ist. Andererseits würde ich, wenn Sie Bytes in Megabytes konvertieren, die Konstante BYTES_PER_MBYTE oder ähnliches definieren, da die Konstante 1.048.576 nicht so offensichtlich ist, dass sie 1024 ^ 2 ist, oder dass es sogar richtig ist.
Gleiches gilt für Werte, die durch Anforderungen oder Standards vorgegeben sind und nur an einer Stelle verwendet werden. Ich finde es einfacher, die Konstante mit einem Kommentar zu der entsprechenden Quelle in Position zu bringen, als sie anderswo zu definieren und beide Teile zu verfolgen, zB:
Finde ich besser als
Nur wenn
SOME_THRESHOLD_VALUE
es an mehreren Stellen verwendet wird, lohnt es sich meiner Meinung nach, eine Konstante zu definieren.quelle
e^i*pi = -1
ist weit expliziter (besser) als2.718^i*3.142 = -1
. Variablen sind wichtig und nicht nur für allgemeinen Code gedacht. Code wird zuerst zum Lesen geschrieben, dann zum Kompilieren. Auch die technischen Daten ändern sich (stark). Während die 1024 wahrscheinlich nicht in der Konfiguration sein sollte, klingt die 3.5 so, wie es sein sollte.1024*1024
PLZ!Ich stelle zwei Fragen, wenn es um magische Zahlen geht.
Hat die Nummer einen Namen?
Namen sind nützlich, weil wir den Namen lesen und den Zweck der dahinter stehenden Nummer verstehen können. Benennungskonstanten können die Lesbarkeit verbessern, wenn der Name leichter zu verstehen ist als die Zahl, die er ersetzt, und der Name der Konstanten präzise ist.
Konstanten wie pi, e et al. haben aussagekräftige Namen. Ein Wert wie 1024 könnte sein,
BYTES_PER_KB
aber ich würde auch erwarten, dass jeder Entwickler weiß, was 1024 bedeutet. Die Zielgruppe für den Quellcode sind professionelle Programmierer, die den Hintergrund haben sollten, die verschiedenen Potenzen von zwei zu kennen und warum sie verwendet werden.Wird es an mehreren Orten verwendet?
Während Namen eine Stärke von Konstanten sind, ist eine andere die Wiederverwendbarkeit. Wenn sich ein Wert wahrscheinlich ändert, kann er an einem Ort geändert werden, anstatt ihn an mehreren Orten suchen zu müssen.
Ihre Frage
Bei Ihrer Frage würde ich die Nummer so verwenden, wie sie ist.
Name: Es gibt einen Namen für diese Nummer, aber es ist nichts wirklich Nützliches. Es stellt keine mathematische Konstante oder einen mathematischen Wert dar, der in einem Anforderungsdokument angegeben ist.
Standorte: Auch wenn es an mehreren Standorten verwendet wird, ändert es sich nie, wodurch dieser Vorteil zunichte gemacht wird.
quelle
Dieses Zitat
wie gesagt von Jörg W Mittag beantwortet diese Frage ganz gut.
Einige Zahlen sind in einem bestimmten Kontext einfach nicht magisch. In dem in der Frage angegebenen Beispiel wurden die Maßeinheiten durch die Variablennamen angegeben, und die durchgeführte Operation war ziemlich klar.
Das
1024
ist also nicht magisch, da der Kontext sehr deutlich macht, dass dies der geeignete, konstante Wert für Conversions ist.Ebenso ein Beispiel für:
ist ebenso klar und nicht magisch, weil es bekanntlich 24 Stunden am Tag gibt.
quelle
24
sowieso nicht verwenden ! Wie Izkata erwähnte, taten Schaltsekunden weh. Vielleicht hättest du besseres Glück, wenn du die Konstante24
auf dem Mars benutzt als auf der Erde!Andere Plakate haben erwähnt, dass die Konvertierung "offensichtlich" ist, aber ich bin anderer Meinung. Die ursprüngliche Frage zu diesem Zeitpunkt umfasst:
Ich weiß also schon, dass der Autor verwirrt ist oder war. Die Wikipedia-Seite fügt der Verwirrung hinzu:
"Kilobyte" kann also sowohl als Faktor 1000 als auch als Faktor 1024 verwendet werden, wobei der einzige Unterschied in der Kurzform die Großschreibung des "k" ist. Darüber hinaus kann 1024 Kilobyte (JEDEC) oder Kibibyte (IEC) bedeuten. Warum nicht die ganze Verwirrung mit einer Konstante mit einem aussagekräftigen Namen auflösen? Übrigens hat dieser Thread häufig "BYTES_PER_KBYTE" verwendet, und das ist nicht weniger zweideutig. KBYTE: ist es KIBIBYTE oder KILOBYTE? Ich würde es vorziehen JEDEC zu ignorieren und haben
BYTES_PER_KILOBYTE = 1000
undBYTES_PER_KIBIBYTE = 1024
. Keine Verwirrung mehr.Der Grund, warum Leute wie ich und viele andere da draußen "militante" (um hier einen Kommentator zu zitieren) Meinungen zum Benennen von magischen Zahlen haben, besteht darin, zu dokumentieren, was Sie vorhaben , und Mehrdeutigkeiten zu beseitigen. Und Sie haben tatsächlich eine Einheit ausgewählt, die zu viel Verwirrung geführt hat.
Wenn ich sehe:
Dann ist sofort klar, was der Autor vorhatte, und es gibt keine Unklarheiten. Ich kann die Konstante in Sekundenschnelle überprüfen (auch wenn sie sich in einer anderen Datei befindet), sodass sie zwar nicht "augenblicklich" ist, aber nahe genug ist, um augenblicklich zu sein.
Am Ende könnte es offensichtlich sein, wenn Sie es schreiben, aber es wird weniger offensichtlich sein, wenn Sie später darauf zurückkommen, und es könnte noch weniger offensichtlich sein, wenn jemand anderes es bearbeitet. Es dauert 10 Sekunden, um eine Konstante zu erstellen. Es kann eine halbe Stunde oder länger dauern, bis ein Problem mit Units behoben ist (der Code wird Sie nicht ansprechen und Ihnen mitteilen, dass die Units falsch sind. und du wirst wahrscheinlich 10 verschiedene Alleen suchen, bevor du Einheiten überprüfst).
quelle
KB
) unterschiedlich definieren, werden nicht helfen.Wenn Sie einen Namen so definieren, dass er sich auf einen numerischen Wert bezieht, bedeutet dies, dass ein anderer Wert an einer Stelle, an der dieser Name verwendet wird, wahrscheinlich in allen Fällen benötigt wird. Es besteht auch die Tendenz, dass das Ändern des dem Namen zugewiesenen numerischen Werts eine legitime Möglichkeit zum Ändern des Werts darstellt. Eine solche Implikation kann nützlich sein, wenn sie wahr ist, und gefährlich, wenn sie falsch ist.
Die Tatsache, dass zwei verschiedene Stellen einen bestimmten Literalwert verwenden (z. B. 1024), deutet schwach darauf hin, dass Änderungen, die einen Programmierer dazu veranlassen würden, einen zu ändern, den Programmierer wahrscheinlich dazu anregen, andere zu ändern, aber diese Implikation ist viel schwächer als zutreffend wenn der Programmierer einer solchen Konstante einen Namen gegeben hat.
Eine große Gefahr bei so etwas
#define BYTES_PER_KBYTE 1024
ist, dass es für jemanden, der darauf stößt,printf("File size is %1.1fkB",size*(1.0/BYTES_PER_KBYTE));
dass ein sicherer Weg, den Code Tausende von Bytes verwenden zu lassen, darin besteht, die#define
Anweisung zu ändern . Eine solche Änderung könnte jedoch verheerend sein, wenn z. B. ein anderer nicht verwandter Code die Größe eines Objekts in KB empfängt und diese Konstante bei der Zuweisung eines Puffers verwendet.Es kann sinnvoll sein, für jeden Zweck, den die Konstante 1024 erfüllt, einen anderen Namen zu verwenden
#define BYTES_PER_KBYTE_FOR_USAGE_REPORT 1024
und#define BYTES_PER_KBYTE_REPORTED_BY_FNOBULATOR 1024
zuzuweisen. Dies würde jedoch dazu führen, dass viele Bezeichner genau einmal definiert und verwendet werden. Außerdem ist es in vielen Fällen am einfachsten zu verstehen, was ein Wert bedeutet, wenn man den Code dort sieht, wo er verwendet wird, und am einfachsten herauszufinden, wo Code bedeutet, wenn man die Werte von darin verwendeten Konstanten sieht. Wenn ein numerisches Literal nur einmal für einen bestimmten Zweck verwendet wird, liefert das Schreiben des Literal an der Stelle, an der es verwendet wird, häufig verständlicheren Code als das Zuweisen einer Bezeichnung an einer Stelle und das Verwenden seines Werts an einer anderen Stelle.quelle
Ich würde gerne nur die Nummer verwenden, aber ich denke, ein wichtiges Thema wurde noch nicht angesprochen: Dieselbe Nummer kann in verschiedenen Kontexten unterschiedliche Bedeutungen haben, was das Refactoring erschweren kann.
1024 ist auch die Anzahl von KiB pro MiB. Angenommen, wir verwenden 1024, um diese Berechnung auch irgendwo oder an mehreren Stellen darzustellen, und müssen jetzt zu ihr wechseln, um stattdessen GiB zu berechnen. Das Ändern der Konstante ist einfacher als ein globales Suchen / Ersetzen, bei dem Sie möglicherweise an einigen Stellen versehentlich die falsche oder an anderen Stellen die falsche Konstante ändern.
Oder es könnte sogar eine Bitmaske sein, die von einem faulen Programmierer eingeführt wurde und eines Tages aktualisiert werden muss.
Es ist ein wenig konstruiertes Beispiel, aber in einigen Codebasen kann dies zu Problemen beim Umgestalten oder Aktualisieren für neue Anforderungen führen. In diesem speziellen Fall würde ich die einfache Zahl jedoch nicht als wirklich schlechte Form betrachten, insbesondere wenn Sie die Berechnung in eine Methode zur Wiederverwendung einschließen können. Ich würde es wahrscheinlich selbst tun, aber die Konstante als "richtiger" betrachten.
Wenn Sie jedoch benannte Konstanten verwenden, ist es, wie Supercat sagt, wichtig zu prüfen, ob der Kontext ebenfalls wichtig ist und ob Sie mehrere Namen benötigen.
quelle