Koddaki her sayı "sihirli sayı" olarak mı kabul edilir?


21

Yani bir metod olarak argüman olarak gönderdiğimiz koddaki her sayı bir Magic Number olarak kabul edilir? Bana göre, olmamalı. Sanırım bazı numaralar minimum kullanıcı adı uzunluğu için diyelim ve kodda "6" kullanmaya başlıyorsak ... o zaman evet bir bakım sorunumuz var ve burada "6" sihirli bir sayı .... eğer argümanlarından birinin bir koleksiyonun üyesi olduğu bir tamsayıyı kabul ettiği bir metot çağırıyorsak, o zaman bu metot çağrısına "0" 'u geçiyoruz, bu durumda "0" ı sihirli olarak görmüyorum numara. Ne düşünüyorsun?


4
Örnekte, 0 neyi temsil ediyor?
Aaron Kurtzhals

2
Gösterdiğiniz durumda, "0" ın herhangi bir büyülü özelliği yoktur.
Tulains Córdova

4
0,1 ve 42 dışındaki her şey sihir
Mawg

Yanıtlar:


43

Sayının anlamı bağlamda çok açıksa, bunun "sihirli sayı" sorunu olduğunu sanmıyorum.

Örnek: Dize bir alt dizgiyi almaya başladığınızı, en baştan bir tokene geldiğini varsayalım ve kod şöyle görünür (hayali dil ve kütüphane)

s := substring(big_string, 0, findFirstOccurence(SOME_TOKEN, big_string));

Bu bağlamda, 0 sayısının anlamı yeterince açıktır. Sanırım onu ​​tanımlayıp START_OF_SUBSTRING0 olarak ayarlayabiliyorsunuz, ancak bu durumda bunun fazladan olacağını düşünüyorum (her ne kadar subring'in başlamasının 0 olmayabileceğini biliyor olsanız da bu doğru bir yaklaşım olsa da, bunun özelliklerine bağlıdır). senin durumun).

Başka bir örnek, bir sayının çift mi yoksa tek mi olduğunu belirlemeye çalışıyorsanız olabilir. Yazı:

isEven := x % 2;

kadar garip değil:

TWO := 2;
isEven := x % TWO;

Negatif sayıları şu şekilde test etme

MINUS_ONE := -1;
isNegativeInt := i <= MINUS_ONE;

Ayrıca bana çok garip geliyor, görmek isterdim

isNegativeInt := i <= -1;

6
Oraya başka bir örnek vermek gerekirse, bir daire üzerinde derece ile açıkça çalıştığınız kodda 360, çoğu insanın bunun ne anlama geldiğini bileceği anlayışıyla tam bir dönüşü işaretlemek gibi bir sayı kullanmak doğru olacaktır (buna rağmen) sabit sağlamak için zarar vermeyeceği bir durumdur )
KChaloux

11
KChaloux: Yapabilseydim, yorumunuzu -1 yapardım. 360 sihirli bir sayıdır. 360 başka bir sabit için bir değerse, 360 ile ilgisiz ve ayırt edilemez olan 2 setiniz olur. Junior geliyor, “Bu sihirli bir sayı”, küresel arama ve 360'ı "Degrees_in_Circle" ile değiştir, tüm birim ve regresyon testlerini çalıştır, tüm kodlar kod çözme işlemlerini gerçekleştirdi. Şimdi köpekler kahvaltısını kodlayın ve kısa bir süre sonra buna ne olacağını hepimiz biliyoruz .......
mattnz

4
@ mattnz: Umarım bu tür büyük ölçekli kod değişikliği, üretime başlamadan çok önce hızlı bir şekilde yakalanır (umarız, kod incelemesi sırasında). Sanırım bu bağlamda bunu yapacak biri muhtemelen 0benim alt dize örneğimin bağlamında da yerini alacak . Bu durumda, bu neden olabilecekleri en az hasar olabilir. Geometrik hesaplamalar yapan herhangi bir kodlama yaptığımdan beri çok uzun zaman geçti, fakat genellikle 15, 30, 45, 60, 90, 180, 360 değerleri kabul edilen sabitlerdi. Hiç kimsenin tanımladığını görmedim FIFTEEN_DEGREES...
Sinir

5
@KChaloux Dereceden Radyan'a geçiş varsa, örnek aslında parçalara ayrılabilir. 360 ile 1 tam dönüş ifade ediyorsunuz. Aynı değer için çoklu gösterimler olduğu için çıkarılmalıdır. Özellikle 360PI 2PI ile aynı görünebilir (180 dönüş ancak yine de aynı yöne işaret eder) veya 360 dönüş 1 dönüşle aynı olabilir, ancak yan etkiler farklı olabilir.
Chris

14
Orada biraz samanlıkta olan bir adam, İKİ ve MINUS_ONE tamamen kötüdür çünkü sihirli bir sayının metin içindeki gösterimi ile değiştirilmesi, DERSİN aptallığıdır. Sabitin adı anlamını iletmek zorundadır. Örnekleriniz, sadece bu belirli numaralara yakından bağlı sayılarla ilgili temel gerçekler hakkında olduğu için, bunun ötesinde gerçekten bir anlamı yoktur.
Michael Borgwardt

17
bool hasApples = apples > 0;

Sıfırın olmadığı anlamına gelir açıktır. "AbsenceValue" adlı bir değişkenden daha kolay anlaşılması 0 buluyorum.


for(int i=0; i < arr.length; i++)

0 başlangıç ​​noktası açıktır. "FirstPosition" adında bir değişkenle karıştırılırdım. Böyle bir değişken, başlangıç ​​pozisyonunun değişip değişmeyeceğini merak etmeme neden olur.


14

Bir şeyin sürekli bir beyan olup olmayacağına karar verirken üç temel faktör önereceğim:

  1. Sayı kesin ve kesin olarak temsil edilebilir bir şey midir?
  2. Değerin değişmesi gereken makul senaryolar var mı, ancak kodun yeniden yazılması gerekmeyecek
  3. Numarayı gören biri, adı verilen bir sabiti gören birinden daha hızlı veya daha az hızlı tanımaya uygun mudur?

Pi gibi bir şey muhtemelen sayısal bir değişmez olarak değil, sayısal bir değişmez, gereksizce ayrıntılı, gereksiz yere kesin olmayan veya her ikisi için de uygun olduğundan, adlandırılmış bir sabit olarak yazılmalıdır. Önbellekteki yuva sayısı gibi bir şey, onu kullanan tüm kodu değiştirmek zorunda kalmadan önbelleği genişletme olasılığına izin vermek için muhtemelen adlandırılmış bir sabit olmalıdır (aşağıdaki nota bakınız). İfadedeki "4", "28" ve "29" sayıları gibi ifadeler if ((year % 4)==0) FebruaryDays = 29; else FebruaryDays = 28;muhtemelen sabit olarak adlandırılmamalıdır, çünkü ifade neredeyse kesinlikle daha okunaklıdır if ((year % YearsBetweenLeapYears)==0) FebruaryDays = FebruaryDaysInLeapYear; else FebruaryDays = FebruaryDaysInNonLeapYear;. Standartları koruyanların, o yıldaki 2100 Şubat uzunluğunun yukarıdaki formülle eşleşmeyeceğini belirttiklerini unutmayın. Bu tür tarihleri ​​doğru bir şekilde işlemeyi engellemek (ör. kod, tamsayı taşması veya bu gibi diğer sorunlardan dolayı tetiklenmeyecektir).

Kural 2 ile önemli bir uyarı, bazı durumlarda kodun, kodlanmış numaralara, adlandırılmış bir sabit ile kolayca temsil edilemeyecek şekilde dayanabileceğidir. Örneğin, ayrık parametreler olarak geçirilen iki vektörün çapraz ürününü hesaplayan bir yöntem, yalnızca üç boyutlu vektörlerde kullanıldığında anlamlı olacaktır. Gerekli boyut sayısı, rutini tamamen yeniden yazmadan anlamlı bir şekilde değiştirilebilecek bir değer değildir. Üç 4 boyutlu vektörün çarpı ürününü hesaplamak için olası bir ihtiyaç öngörülse bile, "3" değeri için adlandırılmış bir sabit kullanmak, bu ihtiyacı karşılamayı kolaylaştırmak için çok az şey yapar.


4

Bu, tüm ilkeler gibi, bir derece meselesidir. Genel olarak konuşursak, kaynak kodundaki değişmezlerin sayısı büyüdüklerinden daha şüphelidir. 10 gibi bir maksimum uzunluk veya 0x587FB0 gibi bir hafıza adresi açık bir şekilde kötü bir uygulamadır - hemen hemen er ya da geç, bu değerleri bir kereden fazla tekrarlamanız, uyumsuzluk riski oluşturmayan ve yanlış olan yerlerde ortaya çıkarılan ince hatalar yaratacağınız kesindir. değişti.

0, ölçeğin diğer ucunda; Hala şüpheli ama pek değil. Bir sentinel değeri olarak 0 kullanıyor musunuz? O zaman muhtemelen bunun yerine sembolik bir sabit kullanmalısınız, çünkü sabit bunun ne anlama geldiğini açıklayabilir . "0 başarılı bir şekilde tamamlanma" anlamına gelen son derece sağlam bir kültürel anlaşma mı? Muhtemelen tamamdır. "Koleksiyondaki ilk öğe" anlamına mı geliyor? Bu zararsız olabilir, ancak alternatif bir yöntem varsa, first()muhtemelen tercih ederim.


1
"Bir sentinel değeri olarak 0 kullanıyor musunuz?" Burada "nöbetçi" ile ne demek istediğinizi açıklayabilir misiniz? Eşleşen gibi bir tanım bulamıyorum.
rory.ap

3

Bağlamdan hemen belli olmayan her isimsiz numara sihirli bir sayıdır. Bağlamdan hemen anlaşılan anlamı olan sayıları tanımlamak biraz saçma.

Django'da (python web framework), bazı veritabanı alanlarını şu gibi ham bir sayı ile tanımlayabilirim:

firstname = models.CharField(max_length=40)
middlename = models.CharField(max_length=40)
lastname =  models.CharField(max_length=40) 

hangisinden daha net (ve önerilen uygulama )

MAX_LENGTH_NAME = 40
...
firstname = models.CharField(max_length=MAX_LENGTH_NAME)
middlename = models.CharField(max_length=MAX_LENGTH_NAME)
lastname =  models.CharField(max_length=MAX_LENGTH_NAME) 

uzunluğunu hiçbir zaman değiştirmem gerekmediği için (ve daima max_lengthalanıyla karşılaştırabilirim). Uygulamayı ilk başlattıktan sonra alanın uzunluğunu değiştirmem gerekiyorsa, django kodumdaki alan başına tam olarak bir konumda değiştirmem ve sonra da DB'nin şemasını değiştirmek için bir geçiş yazmam gerekir. Herhangi max_lengthbir nesne türünün tanımlanmış bir alanını referans almam gerekirse, bunu doğrudan yapabilirim - bu alanlar bir Personsınıf tanımlıyorsa , bunu Person._meta.get_field('firstname').max_lengthelde etmek için kullanabilirim .max_length(tek bir yerde tanımlanmış olan). Aynı 40'ın çoklu alanlar için kullanılmış olması, onları bağımsız olarak değiştirmek isteyebileceğim için alakasız. Adın uzunluğu hiçbir zaman ara adın veya soyadın uzunluğuna bağlı olmamalıdır; bunlar ayrı değerlerdir ve bağımsız olarak değişebilirler.

Genellikle dizi indeksleri adsız numaralar kullanabilir; Örneğin, bir python sözlüğüne koymak istediğim bir CSV dosyam varsa, satırdaki ilk öğeyi keyyazacağım sözlük olarak :

mydict = {}
for row in csv.reader(f):
    mydict[row[0]] = row[1:]

Tabii ki şöyle bir isim index_column = 0yapabilirim:

index_col = 0
mydict = {}
for row in csv.reader(f):
    mydict[row[index_col]] = row[:index_col] + row[index_col+1:]

Daha da kötüsü after_index_col = index_col + 1kurtulmak için tanımlamak index_col+1, ancak bu benim görüşüme göre kodu daha net yapmaz. Ayrıca, index_colbir isim verirsem, sütun 0 olmasa bile kodun çalışmasını daha iyi yaparım (bu nedenle row[:index_col] +bölüm).


7
Aslında, max_lngth=40vs max_length=MAX_LENGTH_NAMEbir olduğunu klasik bir sihirli sayının examlple çığlıkları simgesi olmayı. 45 karakter adını desteklemek istediğiniz gün gelecek ve şimdi "40" ın her kullanımı şüpheli ve dikkatlice incelenmeli.
Ross Patterson,

1
@RossPatterson - Burası sürekli bir global var MAX_ARRAY_SIZE ile karşılaştırdığımız C değil, düzgün bir web çerçevesi. Sihirli sayının ortaya çıktığı tek yer veritabanı modelini bildirdiğiniz yerdir; her şey bu değerle karşılaştırılır (örneğin, 40 kodda başka hiçbir yerde görünmez). Ayrıca, bir DB'ye bağlı olarak şema geçişleri yapmadan bu değişkeni kolayca değiştiremeyeceğinizi unutmayın. Ben kodunda 1 karakter orta isimler değişikliğe onun hemen açık bir yerde söylemek değiştirmek istiyorsa 40için 1. Bağlamı düşünmelisin.
dr jimbob

2
Üzgünüm, iki konuda yanılıyorsun. İlk olarak, OP herhangi bir dil belirtmeyen bir "programlama uygulamaları" sorusu sordu. "İşlev" değil, "yöntem" dediler, bu yüzden nesne yönelimli bir şey varsayalım, ama bu bizi sihirli numaralı veri dünyasının dışına çıkarmaz. İkincisi, eğer sihirli sayı veri tabanına ( örneğin şemaya) yerleştirilmişse, kodda bulunması daha da kötüdür. Yapılacak doğru şey, sihir kaynağından neredeyse sabit bir hale getirmektir - ya veritabanının kendisi ya da kodun kullanım ömrü boyunca değişecek tüm bu sabitleri merkezileştiren bir şema modülü.
Ross Patterson
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.