W ostatnim projekcie musiałem przekonwertować bajty na kilobajty kibibajta . Kod był dość prosty:
var kBval = byteVal / 1024;
Po napisaniu tego resztę funkcji działałem i przeszedłem.
Ale później zacząłem się zastanawiać, czy właśnie umieściłem magiczną liczbę w moim kodzie. Część mnie mówi, że było dobrze, ponieważ liczba jest stałą i powinna być łatwo zrozumiana. Ale inna część mnie uważa, że byłoby bardzo jasne, gdyby było owinięte określoną stałą BYTES_PER_KBYTE
.
Czy więc liczby, które są dobrze znanymi stałymi, są naprawdę tak magiczne, czy nie?
Powiązane pytania:
Kiedy liczba jest magiczną liczbą? i Czy każda liczba w kodzie jest uważana za „magiczną liczbę”? - są podobne, ale mają znacznie szersze pytania niż te, które zadaję. Moje pytanie koncentruje się na dobrze znanych stałych liczbach, które nie zostały uwzględnione w tych pytaniach.
Eliminowanie magicznych liczb: kiedy należy powiedzieć „nie”? jest również powiązany, ale koncentruje się na refaktoryzacji, w przeciwieństwie do tego, czy liczba stała jest liczbą magiczną, czy nie.
źródło
FOUR_HUNDRED_FOUR = 404
. Pracowałem nad innym projektem, w którym bojownikami używali stałych ciągów zamiast literałów, więc mieli dziesiątki wierszy w kodzie, które wyglądały jak:DATABASE = "database"
1024
, bo w przeciwnym razie zespół deweloperów spędza cały swój czas na kłótniach o to, czy są to „kilobajty” czy „kibibajty”.#define
KIBI
jako 1024,MEBI
jako 1024 * 1024…ZERO=0, ONE=1, TWO=2
a kiedy programy zostaną przeniesione do innych języków (lub programiści nie zmienią zachowania podczas zmiany języka), zobaczysz to również tam i musisz się modlić, aby nikt nigdy nie zmienił naONE=2
...Odpowiedzi:
Nie wszystkie magiczne liczby są takie same.
Myślę, że w tym przypadku ta stała jest OK. Problem z liczbami magicznymi polega na tym, że są one magiczne, tzn. Nie jest jasne, jakie jest ich pochodzenie, dlaczego wartość jest tym, czym jest, ani czy wartość jest poprawna, czy nie.
Ukrywanie 1024 za BYTES_PER_KBYTE oznacza również, że nie widzisz od razu, czy jest poprawne, czy nie.
Spodziewałbym się, że ktoś natychmiast wie, dlaczego wartość wynosi 1024. Z drugiej strony, jeśli konwertujesz bajty na megabajty, zdefiniowałbym stałą BYTES_PER_MBYTE lub podobną, ponieważ stała 1 048 576 nie jest tak oczywista, że jej 1024 ^ 2 lub że to nawet poprawne.
To samo dotyczy wartości podyktowanych wymaganiami lub standardami, które są używane tylko w jednym miejscu. Uważam, że umieszczenie stałej z właściwym komentarzem do odpowiedniego źródła jest łatwiejsze w obsłudze niż zdefiniowanie jej gdzie indziej i konieczność ścigania obu części, np .:
Uważam, że lepiej niż
SOME_THRESHOLD_VALUE
Moim zdaniem, tylko gdy jest używany w wielu miejscach, kompromis staje się warty zdefiniowania stałej.źródło
e^i*pi = -1
jest o wiele bardziej wyraźny (lepszy) niż2.718^i*3.142 = -1
. Zmienne mają znaczenie i nie służą tylko do wspólnego kodu. Kod jest napisany do czytania jako pierwszy, kompilowania jako drugi. Zmieniają się też specyfikacje (bardzo dużo). Podczas gdy 1024 prawdopodobnie nie powinno być w konfiguracji, 3.5 brzmi tak, jak powinno być.1024*1024
proszę!Zadaję dwa pytania dotyczące magicznych liczb.
Czy numer ma nazwę?
Nazwy są przydatne, ponieważ możemy odczytać nazwę i zrozumieć cel liczby za nią. Stałe nazewnictwa mogą zwiększyć czytelność, jeśli nazwa jest łatwiejsza do zrozumienia niż liczba, którą zastępuje, a stała nazwa jest zwięzła.
Oczywiście stałe takie jak pi, e i in. mają sensowne imiona. Wartość taka jak 1024 może być,
BYTES_PER_KB
ale oczekiwałbym również, że każdy programista będzie wiedział, co oznacza 1024. Odbiorcami kodu źródłowego są profesjonalni programiści, którzy powinni mieć doświadczenie w poznawaniu różnych potęg dwóch i dlaczego są używane.Czy jest używany w wielu lokalizacjach?
Podczas gdy nazwy stanowią jedną siłę stałych, drugą jest możliwość ponownego użycia. Jeśli wartość może ulec zmianie, można ją zmienić w jednym miejscu, zamiast konieczności szukania jej w wielu lokalizacjach.
Twoje pytanie
W przypadku twojego pytania użyłbym tego numeru w obecnej postaci.
Nazwa: istnieje nazwa dla tego numeru, ale nie jest to tak naprawdę przydatne. Nie reprezentuje stałej matematycznej ani wartości określonej w żadnym dokumencie wymagań.
Lokalizacje: nawet jeśli jest używany w wielu lokalizacjach, nigdy się nie zmieni, co neguje tę korzyść.
źródło
Ten cytat
jak powiedział przez Jörg W Mittag odpowiedzi na to pytanie całkiem dobrze.
Niektóre liczby po prostu nie są magiczne w określonym kontekście. W przykładzie podanym w pytaniu jednostki miary zostały określone przez nazwy zmiennych, a operacja, która miała miejsce, była dość jasna.
To
1024
nie jest magiczne, ponieważ kontekst wyraźnie pokazuje, że jest to odpowiednia, stała wartość do wykorzystania podczas konwersji.Podobnie przykład:
jest równie jasne i nie magiczne, ponieważ dobrze wiadomo, że są 24 godziny na dobę.
źródło
24
! Jak wspomniała Izkata, sekundy przestępne bolą. Może miałbyś więcej szczęścia, używając stałej24
na Marsie niż na Ziemi!Inni plakaty wspominali, że konwersja jest „oczywista”, ale się nie zgadzam. W chwili obecnej pierwotne pytanie obejmuje:
Więc już wiem, że autor jest lub był zdezorientowany. Strona Wikipedii dodaje zamieszanie:
Zatem „Kilobajt” może oznaczać zarówno współczynnik 1000, jak i 1024, przy czym jedyną różnicą w skrótach jest wielkość liter „k”. Ponadto 1024 może oznaczać kilobajt (JEDEC) lub kibibajt (IEC). Dlaczego nie zniszczyć tego zamieszania wprost stałą ze znaczącą nazwą? BTW, ten wątek często używał „BYTES_PER_KBYTE”, i to nie mniej dwuznaczne. KBYTE: czy to KIBIBYTE czy KILOBYTE? Wolałbym zignorować JEDEC i mieć
BYTES_PER_KILOBYTE = 1000
iBYTES_PER_KIBIBYTE = 1024
. Nigdy więcej zamieszania.Powodem, dla którego ludzie tacy jak ja i wielu innych mają „bojujące” (by zacytować tutaj komentatora) opinie na temat nazewnictwa magicznych liczb, jest przede wszystkim udokumentowanie tego, co zamierzasz zrobić, i usunięcie niejasności. I rzeczywiście wybrałeś jednostkę, która doprowadziła do wielu zamieszania.
Jeśli widzę:
Wtedy od razu widać, co zamierzał zrobić autor, i nie ma dwuznaczności. Mogę sprawdzić stałą w ciągu kilku sekund (nawet jeśli jest w innym pliku), więc nawet jeśli nie jest to „natychmiastowe”, jest wystarczająco blisko do natychmiastowej.
W końcu może być oczywiste, gdy piszesz, ale będzie mniej oczywiste, gdy wrócisz do niego później, a może być jeszcze mniej oczywiste, gdy ktoś inny go edytuje. Utworzenie stałej zajmuje 10 sekund; debugowanie problemu z jednostkami może zająć pół godziny lub dłużej (kod nie rzuci się na ciebie i nie powie, że jednostki się mylą, musisz sam wyliczyć matematykę, aby to zrozumieć, i prawdopodobnie polujesz na 10 różnych dróg, zanim sprawdzisz jednostki).
źródło
KB
) inaczej nie pomogą.Zdefiniowanie nazwy jako wartości liczbowej sugeruje, że ilekroć potrzebna jest inna wartość w jednym miejscu, które używa tej nazwy, prawdopodobnie będzie ona potrzebna we wszystkich. Sugeruje również, że zmiana wartości liczbowej przypisanej do nazwy jest uzasadnionym sposobem zmiany wartości. Taka implikacja może być użyteczna, gdy jest prawdziwa, i niebezpieczna, gdy jest fałszywa.
Fakt, że dwa różne miejsca używają konkretnej wartości literalnej (np. 1024), słabo sugeruje, że zmiany, które skłoniłyby programistę do zmiany jednego, mogą raczej zainspirować programistę do zmiany innych, ale ta implikacja jest znacznie słabsza niż miałaby zastosowanie. jeśli programista przypisał nazwę do takiej stałej.
Głównym zagrożeniem związanym z czymś takim
#define BYTES_PER_KBYTE 1024
jest to, że może to sugerować komuś, kto napotka,printf("File size is %1.1fkB",size*(1.0/BYTES_PER_KBYTE));
że bezpiecznym sposobem na użycie kodu w tysiącach bajtów byłaby zmiana#define
instrukcji. Taka zmiana może być katastrofalna, jeśli np. Jakiś inny niepowiązany kod odbierze rozmiar obiektu w kilobajtach i użyje tej stałej przy przydzielaniu do niego bufora.Może być uzasadnione użycie
#define BYTES_PER_KBYTE_FOR_USAGE_REPORT 1024
i#define BYTES_PER_KBYTE_REPORTED_BY_FNOBULATOR 1024
przypisanie innej nazwy dla każdego innego celu obsługiwanego przez stałą 1024, ale spowodowałoby to zdefiniowanie i użycie wielu identyfikatorów dokładnie jeden raz. Co więcej, w wielu przypadkach najłatwiej zrozumieć, co oznacza wartość, jeśli widzi się kod tam, gdzie jest używany, i najłatwiej jest dowiedzieć się, gdzie kod oznacza, jeśli widzi się wartości dowolnej stałej w nim użytej. Jeśli literał liczbowy zostanie użyty tylko raz w określonym celu, napisanie literału w miejscu, w którym jest używany, często daje bardziej zrozumiały kod niż przypisanie etykiety w jednym miejscu i użycie jej wartości w innym miejscu.źródło
Skłoniłbym się do użycia tylko liczby, jednak myślę, że nie poruszono jednego ważnego problemu: ta sama liczba może oznaczać różne rzeczy w różnych kontekstach, co może skomplikować refaktoryzację.
1024 to także liczba KiB na MiB. Załóżmy, że używamy 1024 do reprezentowania tego obliczenia gdzieś lub w wielu miejscach, a teraz musimy to zmienić, aby zamiast tego obliczyć GiB. Zmiana stałej jest łatwiejsza niż globalne wyszukiwanie / zamiana, w której możesz przypadkowo zmienić niewłaściwy w niektórych miejscach lub pominąć go w innych.
Lub może to być nawet maska wprowadzona przez leniwego programistę, który pewnego dnia musi zostać zaktualizowany.
To trochę wymyślony przykład, ale w niektórych bazach kodu może to powodować problemy podczas refaktoryzacji lub aktualizacji pod kątem nowych wymagań. W tym konkretnym przypadku nie uważałbym jednak, że zwykła liczba jest naprawdę złą formą, szczególnie jeśli można zawrzeć obliczenia w metodzie ponownego użycia, prawdopodobnie zrobiłbym to sam, ale uważam, że stała jest bardziej „poprawna”.
Jeśli jednak używasz nazwanych stałych, jak mówi supercat, ważne jest, aby zastanowić się, czy kontekst też ma znaczenie i czy potrzebujesz wielu nazw.
źródło