Sihirli sayı nedir ve neden kötüdür? [kapalı]


514

Sihirli sayı nedir?

Neden kaçınılmalıdır?

Uygun olduğu durumlar var mı?


2
Sihirli numaralardan kaçınmalısınız çünkü kodunuzu görüntüleyen diğer insanlar neden yaptığınızı anlayamıyor olabilirler ... örneğin const myNum = 22; const number = myNum / 11;şu an 11'im insanlar ya da bira şişeleri veya başka bir şey olabilir, bunun yerine 11'i sabit olarak değiştiririm sakinleri gibi.
JuicY_Burrito

Niteliklerde sihirli sayılar kullanmak kaçınılmazdır, bu yüzden bu uygun.
donatasj87

Yanıtlar:


574

Sihirli sayı, koddaki bir sayının doğrudan kullanımıdır.

Örneğin, (Java'da) varsa:

public class Foo {
    public void setPassword(String password) {
         // don't do this
         if (password.length() > 7) {
              throw new InvalidArgumentException("password");
         }
    }
}

Bu, aşağıdakiler için yeniden düzenlenmelidir:

public class Foo {
    public static final int MAX_PASSWORD_SIZE = 7;

    public void setPassword(String password) {
         if (password.length() > MAX_PASSWORD_SIZE) {
              throw new InvalidArgumentException("password");
         }
    }
}

Kodun okunabilirliğini artırır ve bakımı daha kolaydır. GUI'de şifre alanının boyutunu ayarladığım durumu düşünün. Sihirli bir sayı kullanırsam, maksimum boyut her değiştiğinde, iki kod konumunda değişmem gerekir. Birini unutursam, bu tutarsızlıklara yol açacaktır.

JDK in gibi örnekleriyle doludur Integer, Characterve Mathsınıflar.

Not: FindBugs ve PMD gibi statik analiz araçları, kodunuzda sihirli sayıların kullanımını algılar ve yeniden düzenlemeyi önerir.


174
0 ve 1 bu kuralın istisnasıdır.
Jonathan Parker

24
@Kirill: "Yüz Yüzde" tanımının değişmesini bekliyorsanız, evet. Daha iyi bir yaklaşım, değişkenin temsil ettiği şeyden, yani statik statik nihai MAX_DOWNLOAD_PERCENTAGE = 100 değişkenine sahip olmak olacaktır. Bu bile anlamlı olmaz, çünkü "yüzde 100" çok iyi tanımlanmıştır. Öte yandan, Parolaların en fazla 7 karakter uzunluğunda olması, küresel olarak tanımlanmamıştır ve aslında farklıdır, bu nedenle bir değişken için adaydır.
Michael Stum

40
@Jonathan Parker, değiller hariç ( TRUE/ FALSE)
Brendan Long

82
Sihirli bir sayının asla değişmeyeceği, sabit ile değiştirilmemesi gerektiği anlamına gelmez. Kodum HzPerMHz ve msecPerSecond gibi genel sabitlerle doludur. Bunlar asla değişmeyecek, ancak anlamı daha net hale getirecek ve yazım hatalarına karşı bir miktar koruma sağlayacaktır.
Jeanne Pindar

43
@MarcusJ Daha fazla yanlış olamazdın. Bu bir fikir meselesi değil, birçok programcı tarafından zor kazanılmış bir deneyimdir. Geçen 40 yıl boyunca, bir sabiti tanımlamamış önceki bir programcıya kaç kez katlandığımı size söyleyemem, bu yüzden sadece kod bakımı sırasında anlaşılması gereken bir sayının doğrudan kullanımını keşfettim , böyle bir sabit tanımlayarak anlamını açıkça ortaya koyacak olan bir çok kodda bir yere gömüldü. Diğer tüm üst düzey programcıların da bu çizgi boyunca birden fazla korku hikayesi olacaktır.
ToolmakerSteve

145

Sihirli Sayı, daha sonraki bir aşamada değişebilen sabit kodlanmış bir değerdir, bu nedenle güncellenmesi zor olabilir.

Örneğin, "Siparişleriniz" Genel Bakış Sayfasında son 50 Siparişi görüntüleyen bir Sayfanız olduğunu varsayalım. Burada Sihirli Sayı 50'dir, çünkü standart veya konvansiyonla ayarlanmamıştır, spesifikasyonda belirtilen nedenlerle oluşturduğunuz bir sayıdır.

Şimdi, yaptığınız şey 50 farklı yerde - SQL komut dosyanız ( SELECT TOP 50 * FROM orders), Web siteniz (Son 50 Siparişiniz), sipariş giriş bilgileriniz ( for (i = 0; i < 50; i++)) ve muhtemelen birçok başka yerde.

Şimdi, birisi 50'den 25'e değişmeye karar verdiğinde ne olur? veya 75 mi? veya 153? Şimdi her yerde 50'yi değiştirmeniz gerekiyor ve bunu kaçırmanız çok muhtemel. Bul / Değiştir işe yaramayabilir, çünkü 50 başka şeyler için de kullanılabilir ve 50'yi 25 ile körü körüne değiştirmek bazı diğer kötü yan etkilere neden olabilir (örneğin, Session.Timeout = 5025'e ayarlanan ve kullanıcılar çok sık zaman aşımı bildirmeye başlar).

Ayrıca, kodu anlamak zor olabilir, yani " if a < 50 then bla" - karmaşık bir işlevin ortasında karşılaşırsanız, koda aşina olmayan diğer geliştiriciler kendilerine "WTF 50 mi ???"

Bu yüzden tam olarak 1 yerde bu tür belirsiz ve rasgele sayılara sahip olmak en iyisidir - " const int NumOrdersToDisplay = 50", çünkü bu kodu daha okunaklı hale getirir (" if a < NumOrdersToDisplay", aynı zamanda sadece 1 iyi tanımlanmış yerde değiştirmeniz gerekir.

Sihirli Sayıların uygun olduğu yerler, bir standart aracılığıyla tanımlanan her şeydir, yani SmtpClient.DefaultPort = 25veya TCPPacketSize = whatever(bunun standartlaştırılmış olup olmadığından emin değildir). Ayrıca, yalnızca 1 işlevde tanımlanan her şey kabul edilebilir, ancak bu Bağlama bağlıdır.


18
Değişemese bile bu hala kötü bir fikir çünkü neler olduğu belli değil.
Loren Pechtel

11
Her zaman net değil. SmtpClient.DefaultPort = 25muhtemelen açıktır er daha SmtpClient.DefaultPort = DEFAULT_SMTP_PORT.
user253751

4
@immibis Ben kesinlikle DEFAULT_SMTP_PORT kavramını kullanan başka hiçbir kod olmadığını varsayar. Söz konusu uygulama için varsayılan SMTP bağlantı noktası değiştirilirse, tutarsızlık olasılığına neden olarak birden çok yerde güncellenmesi gerekir.
Russ Bradberry

3
Ayrıca, tüm kullanımları bulmak daha zordur - 25uygulamanın her yerinde arama yapmanız ve 25örneğin bir tablo sütununun genişliği veya sayısı olan 25'leri değil, yalnızca SMTP Bağlantı Noktası için olanları değiştirdiğinizden emin olmanız gerekir. sayfada gösterilecek kayıtların listesi.
Michael Stum

2
Bu örnekte, kodun 25 değil, SmtpClient.DefaultPort kullanmasını beklerdim. Yani tek bir yerde değiştirmek zorunda kalacaksınız. Ve bağlantı noktası numarasının aynı kalması muhtemeldir, rastgele bir sihirli sayı değil, atanan bir sayıdır IANA.
njsg

34

Sihirli numara için Wikipedia girişine baktın mı?

Sihirli sayı referansının tüm yolları hakkında biraz ayrıntıya girer. İşte kötü bir programlama uygulaması olarak sihirli sayı hakkında bir alıntı

Sihirli sayı terimi, açıklama yapmadan sayıları doğrudan kaynak kodunda kullanmanın kötü programlama uygulamasına da işaret eder. Çoğu durumda bu, programların okunmasını, anlaşılmasını ve sürdürülmesini zorlaştırır. Çoğu kılavuz sıfır ve bir sayıları için bir istisna oluştursa da, koddaki diğer tüm sayıları adlandırılmış sabitler olarak tanımlamak iyi bir fikirdir.


8
RTFW için iyi bir örnek :)
Eva

Cevabın dolu olmaktan uzak olduğunu söyleyebilirim.
Skeeve

25

Sihirli Sayı Vs. Sembolik Sabit: Ne zaman değiştirilir?

Büyü: Bilinmeyen anlambilim

Sembolik Sabit -> Kullanım için hem doğru semantik hem de doğru bağlam sağlar

Anlamsal: Bir şeyin anlamı veya amacı.

"Bir sabit oluşturun, anlamdan sonra adlandırın ve sayıyı onunla değiştirin." - Martin Fowler

İlk olarak, sihirli sayılar sadece sayılar değildir. Herhangi bir temel değer "büyü" olabilir. Temel değerler, tamsayılar, gerçekler, çiftler, kayan noktalar, tarihler, dizeler, booleans, karakterler vb. Gibi tezahür varlıklardır. Sorun veri türü değil, kod metnimizde göründüğü gibi değerin "sihirli" yönüdür.

"Büyü" ile ne demek istiyoruz? Kesin olmak gerekirse: "Büyü" ile, kodumuz bağlamında değerin anlambilimine (anlam veya amaç) işaret etmeyi amaçlıyoruz; bilinmeyen, bilinemez, belirsiz veya kafa karıştırıcı. Bu "büyü" nosyonudur. Semantik anlamı veya var olma amacı, özel yardımcı kelimeler (örn. Sembolik sabit) olmadan çevre bağlamından hızlı ve kolay bir şekilde bilinir, anlaşılır ve anlaşılırsa (kafa karıştırıcı değildir) temel bir değer sihirli değildir.

Bu nedenle, bir kod okuyucunun çevredeki bağlamdan temel bir değerin anlamını ve amacını bilme, açık olma ve anlama yeteneğini ölçerek sihirli sayıları belirleriz. Okuyucu ne kadar az bilinirse, o kadar az anlaşılır ve kafan karışırsa, temel değer o kadar "büyü" olur.

Yardımcı Tanımlar

  • karıştırmayın: (birinin) şaşkına dönmesine veya şaşkına dönmesine neden olun.
  • şaşkın: (birinin) şaşkın ve karışık olmasına neden olun.
  • çapraşık: tamamen şaşkın; çok şaşkın.
  • şaşkın: tamamen daha şaşkın veya şaşkın.
  • şaşkın: anlayamıyorum; şaşkın.
  • anlayın: amaçlanan anlamını (kelimeler, dil veya konuşmacı) algılayın.
  • Anlamı: bir kelime, metin, kavram ya da eylemle kastedilen.
  • kastedilen: iletmek, belirtmek veya referans vermek (belirli bir şey veya kavram); anlamına gelir.
  • belirtmek: belirtisi olmak.
  • endikasyon: bir şeyi gösteren bir işaret veya bilgi parçası.
  • belirtmek: işaret etmek; göstermek.
  • işareti: varlığı veya oluşumu başka bir şeyin olası varlığını veya oluşumunu gösteren bir nesne, kalite veya olay.

temeller

Sihirli temel değerlerimiz için iki senaryomuz var. Programcılar ve kodlar için sadece ikincisi birincil öneme sahiptir:

  1. Anlamının bilinmediği, bilinemez, belirsiz veya kafa karıştırıcı olduğu yalnız bir temel değer (örn. Sayı).
  2. Bağlamda temel bir değer (örn. Sayı), ancak anlamı bilinmemektedir, bilinemez, belirsiz veya kafa karıştırıcıdır.

"Sihir" in kapsayıcı bir bağımlılığı, yalnız temel değerin (örn. Sayı) yaygın olarak bilinen bir anlambilimine (Pi gibi) sahip olmadığı, ancak bağlamdan tamamen açık olmayan veya kötüye kullanılabilen yerel olarak bilinen bir anlambilime (ör. Programınız) sahip olmasıdır. iyi veya kötü bağlam (lar) da.

Çoğu programlama dilinin anlambilimi, (belki de) veri (yani veri tabloları) dışında yalnız temel değerleri kullanmamıza izin vermez. "Sihirli sayılar" ile karşılaştığımızda, bunu genellikle bir bağlam içinde yaparız. Bu nedenle,

"Bu sihirli sayıyı sembolik bir sabitle değiştirir miyim?"

dır-dir:

"Sayının anlamsal anlamını (orada olma amacı) bağlamında ne kadar hızlı değerlendirebilir ve anlayabilirsiniz?"

Bir Tür Sihir ama tam olarak değil

Bu düşünce göz önünde bulundurularak, Pi (3.14159) gibi bir sayının uygun bağlamda yerleştirildiğinde nasıl "sihirli sayı" olmadığını hızlı bir şekilde görebiliriz (örneğin, 2 x 3.14159 x yarıçapı veya 2 * Pi * r). Burada, 3.14159 sayısı, sembolik sabit tanımlayıcı olmadan zihinsel olarak tanınan Pi'dir.

Yine de, genellikle 3.14159'u sayının uzunluğu ve karmaşıklığı nedeniyle Pi gibi sembolik bir sabit tanımlayıcı ile değiştiriyoruz. Pi'nin uzunluk ve karmaşıklık yönleri (doğruluk ihtiyacı ile birleştiğinde) genellikle sembolik tanımlayıcı veya sabitin hataya daha az eğilimli olduğu anlamına gelir. "Pi" nin bir isim olarak tanınması sadece uygun bir bonusdur, fakat sabite sahip olmanın birincil nedeni değildir.

Bu sırada çiftliğin arkasında

Pi gibi ortak sabitleri bir kenara bırakarak, öncelikle özel anlamları olan sayılara odaklanalım, ancak bu anlamların yazılım sistemimizin evreniyle kısıtlandığı. Böyle bir sayı "2" olabilir (temel bir tamsayı değeri olarak).

2 sayısını tek başına kullanırsam, ilk sorum şu olabilir: "2" ne anlama geliyor? "2" nin anlamı tek başına bilinmeyen ve bilinmeyen, kullanımı belirsiz ve kafa karıştırıcıdır. Yazılımımızda sadece "2" olması dil semantiği nedeniyle gerçekleşmeyecek olsa da, "2" nin tek başına özel bir anlambilim veya açık bir amaç taşımadığını görmek istiyoruz.

Yalnız "2" yi şu içeriğe koyalım: padding := 2burada bağlam "GUI Container" dır. Bu bağlamda 2'nin anlamı (piksel veya başka bir grafik birim olarak) bize anlambilimi (anlam ve amaç) hakkında hızlı bir tahminde bulunur. Burada durabilir ve bu bağlamda 2'nin iyi olduğunu ve bilmemiz gereken başka bir şey olmadığını söyleyebiliriz. Ancak, belki de yazılım evrenimizde bu hikayenin tamamı değildir. Daha fazlası var, ama bir bağlam olarak "padding = 2" bunu ortaya çıkaramaz.

Programımızdaki piksel dolgusu olarak 2'nin sistemimizdeki "default_padding" çeşidinde olduğunu varsayalım. Bu nedenle, talimatı yazmak padding = 2yeterince iyi değildir. "Varsayılan" kavramı ortaya çıkmaz. Sadece yazdığım zaman: padding = default_paddingbir bağlam olarak ve sonra başka bir yerde: default_padding = 2sistemimizde 2'nin daha iyi ve daha dolgun bir anlamını (anlamsal ve amaç) tam olarak anlıyorum.

Yukarıdaki örnek oldukça iyi çünkü tek başına "2" herhangi bir şey olabilir. Anlayış aralığını ve etki alanını yalnızca "programım" default_paddingın GUI UX bölümlerinde 2 olan "programım" ile sınırladığımızda, nihayet uygun bağlamda "2" yi anlamlandırırız. Burada "2", "kodum" default_paddingun GUI UX default_paddingkapsamı içinde, çevreleyen kodun daha büyük bağlamında hızlı bir şekilde anlaşılmasını sağlamak için, sembolik bir sabit olarak hesaplanan bir "sihirli" sayıdır .

Dolayısıyla, anlamı (anlamsal ve amaç) yeterince ve hızlı bir şekilde anlaşılamayan herhangi bir temel değer, temel değerin (örn. Sihirli sayı) yerine sembolik bir sabit için iyi bir adaydır.

Daha İleri

Ölçekteki sayılar semantik de olabilir. Örneğin, bir canavar kavramına sahip olduğumuz bir D&D oyunu yapıyoruz gibi davranın. Canavar nesnemiz, life_forcetamsayı olarak adlandırılan bir özelliğe sahiptir . Sayılar, anlam sağlayacak sözcükler olmadan bilinemez veya net olmayan anlamlara sahiptir. Böylece, keyfi olarak şunu söyleyerek başlarız:

  • full_life_force: INTEGER = 10 - Çok canlı (ve zarar görmemiş)
  • minimum_life_force: INTEGER = 1 - Zar zor yaşıyor (çok yaralı)
  • dead: INTEGER = 0 - Ölü
  • undead: INTEGER = -1 - Min undead (neredeyse ölü)
  • zombi: INTEGER = -10 - Maksimum ölümsüz (çok ölümsüz)

Yukarıdaki sembolik sabitlerden, D & D oyunumuzdaki canavarlarımız için canlılık, ölüm ve "ölümsüzlük" (ve olası sonuçlar) hakkında zihinsel bir resim elde etmeye başlarız. Bu kelimeler olmadan (sembolik sabitler), sadece sayılar arasında kalırız -10 .. 10. Sadece kelimelerin olmadığı aralık bizi oyunun farklı bölümlerinin attack_elvesveya gibi çeşitli işlemlere ne anlama geldiğine bağlıysa, muhtemelen büyük karışıklık ve potansiyel olarak oyunumuzdaki hatalarla dolu bir yerde bırakır seek_magic_healing_potion.

Bu nedenle, "sihirli sayıları" ararken ve değiştirirken, yazılımımızın kapsamındaki sayılar ve hatta sayıların birbiriyle anlamsal olarak nasıl etkileşime girdiğiyle ilgili çok amaçlı sorular sormak istiyoruz.

Sonuç

Hangi soruları sormamız gerektiğini gözden geçirelim:

Sihirli bir numaranız olabilir ...

  1. Temel değerin, yazılım evreninizde özel bir anlamı veya amacı olabilir mi?
  2. Özel anlam veya amaç, uygun bağlamında bile bilinmeyebilir, bilinemez, belirsiz veya kafa karıştırıcı olabilir mi?
  3. Uygun bir temel değer yanlış bağlamda kötü sonuçlarla uygunsuz bir şekilde kullanılabilir mi?
  4. Uygun olmayan bir temel değer, doğru bağlamda kötü sonuçlar doğuracak şekilde kullanılabilir mi?
  5. Temel değerin, belirli bağlamlardaki diğer temel değerlerle semantik veya amaç ilişkileri var mı?
  6. Kodumuzda her biri farklı anlambilim ile birden fazla yerde temel bir değer olabilir mi, böylece okuyucumuzun kafa karışıklığına neden olabilir mi?

Kod metninizde tek başına manifest sabit temel değerleri inceleyin. Her bir soruyu böyle bir değerin her bir örneği hakkında yavaş ve düşünceli bir şekilde sorun. Cevabınızın gücünü düşünün. Çoğu zaman, cevap siyah ve beyaz değildir, ancak yanlış anlaşılmış anlam ve amaç, öğrenme hızı ve anlama hızı tonlarına sahiptir. Ayrıca, etrafındaki yazılım makinesine nasıl bağlandığını da görmek gerekir.

Sonunda, değiştirmenin cevabı, bağlantıyı yapmak için okuyucunun kuvvetini veya zayıflığını ölçmek (zihninizde) (örn. "Anlayın"). Anlam ve amacı ne kadar çabuk anlarlarsa, o kadar az "sihir" elde edersiniz.

SONUÇ: Temel değerleri yalnızca sihir, karışıklıklardan kaynaklanan hataları tespit etmek zor olacak kadar büyük olduğunda sembolik sabitlerle değiştirin.


1
Teşekkürler. Meslektaşlarımın yüklemeye devam ettiği statik analiz araçlarını sihirli sayılardan şikayet etmeye devam edin - ama bir aracın anlambilimi nasıl anlaması gerekiyor? Sonuç TÜM temel değerlerin sembolik sabitlerle değiştirilmesidir. Sonucunuza katıldığım için bunu idealden daha az buluyorum.
Chomeh

17

Sihirli sayı, bir dosya biçiminin veya protokol değişiminin başlangıcındaki karakter dizisidir. Bu numara bir sağlık kontrolü olarak işlev görür.

Örnek: Herhangi bir GIF dosyasını açın, en başta göreceksiniz: GIF89. "GIF89" sihirli sayıdır.

Diğer programlar bir dosyanın ilk birkaç karakterini okuyabilir ve GIF'leri düzgün bir şekilde tanımlayabilir.

Tehlike, rastgele ikili verilerin aynı karakterleri içerebilmesidir. Ancak bu pek olası değildir.

Protokol değişimine gelince, size iletilmekte olan geçerli 'mesajın' bozuk veya geçersiz olduğunu hızlı bir şekilde tanımlamak için kullanabilirsiniz.

Sihirli sayılar hala faydalıdır.


13
Onun bahsettiği sihirli sayı olduğunu sanmıyorum
Marcio Aguiar

4
Belki de eklediğiniz "dosya biçimi" ve "ağ iletişimi" etiketlerini kaldırmalısınız çünkü bu tür sihirli numaralardan açıkça bahsetmiyor.
Landon

9
Sihirli sayıların bir kod sorunundan daha fazlasını ifade edebileceğini bilmek hala çok yararlıdır. -Adam
Adam Davis

3
Konu: "Kaynak kodu açısından sihirli bir sayı nedir" yazıyorsa, etiketler orada olmamalıdır. Ama bunu belirtmedi. Ekstra bilgilerime sahip olmak iyi. Bence Kyle, Landon ve Marcio yanılıyor.
Brian R. Bondy

4
Hangisini aradığını belirlemenin de bir yolu yoktu. İlk yazı olduğumdan beri hangisini aradığını tahmin edemedim.
Brian R. Bondy

12

Programlamada, bir "sihirli sayı" sembolik bir ad verilmesi gereken bir değerdir, ancak bunun yerine koda değişmez olarak, genellikle birden fazla yerde yerleştirilir.

SPOT'un (Tek Doğruluk Noktası) iyi olmasının nedeni de kötü: Bu sabiti daha sonra değiştirmek isterseniz, her örneği bulmak için kodunuzu araştırmanız gerekir. Aynı zamanda kötüdür, çünkü bu sayının neyi temsil ettiği diğer programcılara, dolayısıyla "büyüye" açık olmayabilir.

İnsanlar bazen bu sabitleri yapılandırma olarak hareket etmek için ayrı dosyalara taşıyarak sihirli sayıları yok ederler. Bu bazen yararlıdır, ancak değerinden daha fazla karmaşıklık da yaratabilir.


Maginc numaralarını neden ortadan kaldırdığınıza daha açık olabilir misiniz?
Marcio Aguiar

E ^ pi + 1 = 0 gibi matematik formüllerinde
Jared Updike

5
Marcio: "Const int EIGHT = 8;" gibi şeyler yaptığınızda ve sonra gereksinimler değişir ve "const int EIGHT = 9;"
jmucchiello

6
Maalesef, bu sadece kötü adlandırma örneği veya sabit için temel kullanım örneği.
Kzqai

1
@MarcioAguiar: Bazı platformlarda, gibi bir ifade (foo[i]+foo[i+1]+foo[i+2]+1)/3bir döngüden çok daha hızlı değerlendirilebilir. Eğer 3kod bir döngü olarak yeniden yazılmadan değiştirilecek olsaydı , ITEMS_TO_AVERAGEtanımlı olarak gören kişi kodu 3değiştirebileceğini 5ve kod ortalamasının daha fazla öğeye sahip olabileceğini düşünebilirdi . Bunun aksine, ifadeye gerçek kelimeyle bakan biri, birlikte toplanan öğelerin sayısını temsil ettiğini 3fark 3eder.
supercat

10

Sihirli bir sayı, özel, sabit kodlu semantik içeren bir sayı da olabilir. Örneğin, bir zamanlar> 0 kayıt kimliklerinin normal olarak işlendiği, 0'ın kendisinin "yeni kayıt" olduğu, -1'in "bu kök olduğu" ve -99'un "kökte oluşturulduğu" bir sistem gördüm. 0 ve -99, WebService'in yeni bir kimlik sağlamasına neden olur.

Bunun kötü yanı, bir alanı (kayıt kimlikleri için imzalı tamsayıların) özel yetenekler için yeniden kullanmanızdır. Belki hiçbir zaman 0 kimliği veya negatif kimliği olan bir kayıt oluşturmak istemezsiniz, ancak olmasa bile, koda veya veritabanına bakan herkes bununla karşılaşabilir ve ilk başta karıştırılabilir. Bu özel değerlerin iyi belgelenmediğini söylemeye gerek yok.

Muhtemelen 22, 7, -12 ve 620 de sihirli sayılar olarak sayılır. ;-)


10

Sihirli sayılar kullanıldığında bahsedilmeyen bir sorun ...

Çok fazla varsa, sihirli sayıları kullandığınız, değerlerin aynı olduğu iki farklı amaca sahip olma ihtimaliniz oldukça iyidir .

Ve sonra, yeterince, değeri değiştirmeniz gerekiyor ... sadece bir amaç için.


Bu sayılar hakkında konuşurken o kadar olası görünmüyor (en azından bana değil), ama ben dizelerle koştum ve bir hit: ilk olarak, nerede kullanıldığını görmek için çok fazla kod okumalısınız, sizden farklı şeyler için kullanıldığını fark etmeliyim ... en sevdiğim eğlence değil.
Tomislav Nakic-Alfirevic

4

Bunun önceki sorunuza vermiş olduğum cevaba bir yanıt olduğunu varsayıyorum . Programlamada sihirli bir sayı, açıklama yapmadan görünen gömülü bir sayısal sabittir. İki farklı yerde görünürse, bir örneğin değiştirildiği ve başka bir örneğin değiştirildiği koşullara yol açabilir. Bu iki nedenden ötürü, sayısal sabitleri kullanıldıkları yerlerin dışında izole etmek ve tanımlamak önemlidir.


3

Her zaman hızlı bir geçerlilik kontrolü olarak doğrulanabilen bir veri yapısı içinde saklanan belirsiz bir değer olarak "sihirli sayı" terimini farklı şekilde kullandım. Örneğin, gzip dosyaları ilk üç baytı 0x1f8b08 içerir, Java sınıfı dosyaları 0xcafebabe, vb. İle başlar.

Sıklıkla dosya formatlarında gömülü sihirli sayılar görürsünüz, çünkü dosyalar oldukça karışık bir şekilde gönderilebilir ve bunların nasıl oluşturulduğuyla ilgili meta verileri kaybedebilir. Ancak sihirli sayılar bazen ioctl () çağrıları gibi bellek içi veri yapıları için de kullanılır.

Dosya veya veri yapısını işlemeden önce sihirli sayının hızlı bir şekilde kontrol edilmesi, girişin tam bir balderdash olduğunu duyurmak için potansiyel olarak uzun işlemlerle tamamen hata yapmak yerine, hataları erkenden bildirmesini sağlar.


2

Bazen kodunuzda yapılandırılamayan "sabit kodlanmış" numaralar istediğinizi belirtmek gerekir. Optimize edilmiş ters kare kök algoritmasında kullanılan 0x5F3759DF dahil olmak üzere bir dizi ünlü var .

Bu tür Sihirli Numaraları kullanma ihtiyacını bulduğum nadir durumlarda, kodumda bir sabit olarak ayarladım ve neden kullanıldıklarını, nasıl çalıştıklarını ve nereden geldiklerini belgeledim.


1
Bence, sihirli sayı kodu kokusu özellikle açıklanamayan sabitlere atıfta bulunuyor . Onları adlandırılmış bir sabite koyduğunuz sürece, bu bir sorun olmamalı.
Don Kirkby

2

Sınıfın en üstünde bir değişkeni varsayılan bir değerle başlatmaya ne dersiniz? Örneğin:

public class SomeClass {
    private int maxRows = 15000;
    ...
    // Inside another method
    for (int i = 0; i < maxRows; i++) {
        // Do something
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }

    public int getMaxRows() {
        return this.maxRows;
    }

Bu durumda, 15000 sihirli bir sayıdır (CheckStyles'e göre). Bana göre, varsayılan bir değer ayarlamak iyidir. Yapmak istemiyorum:

private static final int DEFAULT_MAX_ROWS = 15000;
private int maxRows = DEFAULT_MAX_ROWS;

Bu okumayı zorlaştırıyor mu? CheckStyles'i yükleyene kadar bunu hiç düşünmedim.


Yapıcı değeri başlatırsa, bu iyi olacağını düşünüyorum. Aksi takdirde değer yapıcı dışında başlatılırsa, bunu sadece bir güçlük ve okunması daha zor bir şey olarak görüyorum.
Thomas Eding

Bence static finalbunları tek bir yöntemde kullandığınızda sabitler aşırıya kaçıyor. finalYöntemin üstünde bildirilen bir değişken daha okunabilir IMHO'dur.
Eva

0

@ eed3si9n: '1'in sihirli bir sayı olduğunu bile söyleyebilirim. :-)

Sihirli sayılarla ilgili bir ilke, kodunuzun ele aldığı her gerçeğin tam olarak bir kez beyan edilmesi gerektiğidir. Kodunuzda sihirli sayılar kullanırsanız (@marcio'nun verdiği şifre uzunluğu örneği gibi, bu gerçeği kolayca çoğaltabilirsiniz ve bu gerçeği anladığınız zaman bir bakım sorununuz vardır.


5
IOW kodu şu şekilde yazılmalıdır:factorial n = if n == BASE_CASE then BASE_VALUE else n * factorial (n - RECURSION_INPUT_CHANGE); RECURSION_INPUT_CHANGE = 1; BASE_CASE = 0; BASE_VALUE = 1
Thomas Eding

0

Dönüş değişkenleri ne olacak?

Saklı yordamları uygularken özellikle zorlayıcı buluyorum .

Bir sonraki saklı yordamı düşünün (yanlış bir sözdizimi, biliyorum, sadece bir örnek göstermek için):

int procGetIdCompanyByName(string companyName);

Belirli bir tabloda varsa şirketin kimliğini döndürür. Aksi takdirde -1 döndürür. Her nasılsa sihirli bir sayı. Şimdiye kadar okuduğum önerilerden bazıları, böyle bir şey yapmak zorunda kalacağımı söylüyor:

int procGetIdCompanyByName(string companyName, bool existsCompany);

Bu arada, şirket yoksa ne dönmeli? Tamam: existesCompany değerini yanlış olarak ayarlar , ancak -1 döndürür.

Antoher seçeneği iki ayrı işlev yapmaktır:

bool procCompanyExists(string companyName);
int procGetIdCompanyByName(string companyName);

Dolayısıyla, ikinci saklı yordam için bir ön koşul şirketin mevcut olmasıdır.

Ama eşzamanlılıktan korkuyorum, çünkü bu sistemde bir şirket başka bir kullanıcı tarafından oluşturulabilir.

Bu arada sonuç olarak: bir şeyin başarısız olduğunu veya bir şeyin mevcut olmadığını söylemek için nispeten bilinen ve güvenli olan bu tür "sihirli sayılar" kullanmak hakkında ne düşünüyorsunuz?


Bu özel durumda, işlevin dokümantasyonu negatif bir dönüş değerinin şirket bulunmadığı anlamına gelirse, sabit kullanmak için bir neden yoktur.
Vincent Fourmond

-1

Bir sihirli sayıyı sabit olarak çıkarmanın bir diğer avantajı, işletme bilgilerini açıkça belgeleme imkanı verir.

public class Foo {
    /** 
     * Max age in year to get child rate for airline tickets
     * 
     * The value of the constant is {@value}
     */
    public static final int MAX_AGE_FOR_CHILD_RATE = 2;

    public void computeRate() {
         if (person.getAge() < MAX_AGE_FOR_CHILD_RATE) {
               applyChildRate();
         }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.