Tüm büyü sayıları aynı mı yaratıldı?


77

Yeni bir projede, bayttan kilobayt kibibite dönüştürmem gerekiyordu . Kod yeterince basitti:

var kBval = byteVal / 1024;

Bunu yazdıktan sonra, fonksiyonun geri kalanını çalışmaya & devam ettirdim.

Fakat daha sonra, koduma yalnızca bir sihirli sayı yerleştirip girmediğimi merak etmeye başladım . Bir kısmı bunun iyi olduğunu söylüyor, çünkü sayı sabit bir sabittir ve kolayca anlaşılması gerekir. Ama benim bir başka tarafım, tanımlanmış bir sabit gibi sarılırsa çok net olacağını düşünüyor BYTES_PER_KBYTE.

Peki, iyi bilinen sabitler gerçekten büyülü olsun ya da olmasın?


İlgili sorular:

Sayı ne zaman sihirli bir sayıdır? ve Koddaki her sayı "sihirli sayı" olarak mı kabul edilir? - benzer, ancak sorduğumdan çok daha geniş sorular. Benim sorum, bu sorularda ele alınmayan bilinen sabit sayılara odaklanmıştır.

Sihirli Sayıları Silme: "Hayır" deme zamanı ne zaman? aynı zamanda ilişkilidir ancak sabit bir sayının sihirli bir sayı olup olmadığına karşı yeniden düzenlemeye odaklanmıştır.


17
Aslında onlar gibi sabitler yarattıkları bir proje üzerinde çalıştım FOUR_HUNDRED_FOUR = 404. Değişmezler yerine sabit dizeleri kullanma konusunda militan oldukları başka bir projede çalıştım, bu yüzden kod gibi görünen onlarca satır vardı ,DATABASE = "database"
Rob

82
Kesinlikle kullanın 1024, çünkü aksi halde dev ekibiniz tüm zamanını "kilobayt" mı yoksa "kibibit" mi olduğunu tartışarak geçirir.
Steven Burnap

6
1024'ün kibi ve #define KIBI1024 olarak, MEBI1024 * 1024 olarak ...
ysdx

6
@ Rob Y: Eski güzel Fortran programcılarına benziyor. Çünkü bu programlama dili programcıları bunu yapmaya zorladı . Evet, ZERO=0, ONE=1, TWO=2programların başka dillere taşınması gibi (veya programlayıcılar dillerini değiştirirken davranışını değiştirmez) gibi sabitleri göreceksiniz ve orada da göreceksiniz ve asla birinin asla değişmemesi için dua etmelisiniz ONE=2
Holger

4
@NoctisSkytower Ekibimiz, kullandığımız birden fazla dil ve bu diller arasında potansiyel olarak tutarsız uygulama nedeniyle bit kaydırma operatörleri yerine açık bölüm ifadeleri kullanmayı tercih ediyor. Aynı şekilde, negatif değerler deşifçe kaydırma ile tutarsız bir şekilde ele alınır. Olumsuz bayt değerlerine sahip olmamız gerekmese de, dönüştürdüğümüz diğer ölçü birimlerinde kesinlikle negatif değerlere sahibiz.

Yanıtlar:


103

Tüm sihirli sayılar aynı değil.

Bence bu durumda, bu sabit Tamam Sihirli sayılarla ilgili sorun, sihir oldukları zaman, yani kökenlerinin ne olduğu, değerin neden olduğu veya değerin doğru olup olmadığı belirsizdir.

1024'ü BYTES_PER_KBYTE’n ardına saklamak, doğru olup olmadığını anında göremeyeceğiniz anlamına da gelir.

Değerin neden 1024 olduğunu hemen kimsenin bilmesini beklerdim. Öte yandan, baytları megabayta dönüştürüyorsanız, BYTES_PER_MBYTE sabitini ya da benzerini tanımlardım çünkü 1.048.576 sabiti 1024 ^ 2 kadar açık değildir. bu doğru bile.

Aynı şey, sadece bir yerde kullanılan gereksinimler veya standartlar tarafından belirtilen değerler için de geçerlidir. İlgili sabiti bir yorumla sabit hakkın yerine koymanın, başka yerde tanımlamaktan ve her iki parçayı kovalamaktan daha kolay başa çıkmanın kolay olduğunu düşünüyorum, örneğin:

// Value must be less than 3.5 volts according to spec blah.
SomeTest = DataSample < 3.50

Daha iyi buluyorum

SomeTest = DataSample < SOME_THRESHOLD_VALUE

SOME_THRESHOLD_VALUEBence sadece çoklu yerlerde kullanıldığında, değişmeyecek bir sabit tanımlamaya değecektir.


67
"Sihirli zaman sihirli sayılar ile sorundur" - Bu tür o kavramın parlak bir açıklama! Ciddi oluyorum! Sadece bu cümle için +1.
Jörg W Mittag

20
İşte yeni geldiğim şey: "sorun olan sayı değil, sihir."
Jörg W Mittag

10
1024 kime açıktır? Her sihir sayısının gerekçesi bu değil mi? Tüm sihirli sayılar kullanılır, çünkü onları kimin yazdığı bellidir. 9.8 de belli değil mi? Benim için yeryüzündeki yer çekiminin hızlanması oldukça açık, ama yine de sabit bir şey yaratacağım, çünkü benim için açık olan başka biri için açık olmayabilir.
Tulains Córdova

15
Hayır. "Daha iyi" örneğinizdeki gibi bir yorum büyük bir kırmızı bayraktır. O sırada yazan kişinin okunabilirlik testini bile geçmeyen koddur. Bir örnek vereceğim. e^i*pi = -1olduğundan daha açık (daha iyi) 2.718^i*3.142 = -1. Değişkenler önemlidir ve bunlar yalnızca genel kod için değildir. İlk okuma için ikinci, derleme için kod yazılır. Ayrıca, özellikler değişir (çok). 1024 muhtemelen config içinde olmamalıdır ancak 3.5 olması gerektiği gibi sesler.
Nathan Cooper

51
Ben de 1024 ^ 2 için bir sabit kullanmazdım; 1024*1024plz!
Yörüngede Hafiflik Yarışları

44

Sihirli sayılara gelince sorduğum iki soru var.

Numaranın bir adı var mı?

İsimler yararlıdır çünkü ismini okuyabilir ve arkasındaki sayının amacını anlayabiliriz. Adlandırma sabitleri olabilir adı o replace sayıdan daha anlamak daha kolay ise okunabilirliği artırmak ve sürekli isim özlü olduğunu.

Açıkçası, pi, e ve diğerleri gibi sabitler. anlamlı isimleri var. 1024 gibi bir değer olabilir, BYTES_PER_KBancak herhangi bir geliştiricinin 1024'ün ne anlama geldiğini bilmesini beklerdim. Kaynak kod için hedef kitle, ikisinin çeşitli güçlerini ve neden kullanıldıklarını bilme geçmişi olan profesyonel programcılardır.

Birden fazla yerde mi kullanılıyor?

İsimler sabitlerin bir kuvveti olsa da, bir başkası yeniden kullanılabilirliktir. Bir değerin değişmesi muhtemel ise, birden fazla yerde arama yapmak zorunda kalmak yerine tek bir yerde değiştirilebilir.

Senin sorun

Sorunuz durumunda, sayıyı olduğu gibi kullanırım.

İsim: bu numara için bir isim var, ama gerçekten işe yaramaz bir şey değil. Herhangi bir gereksinim belgesinde belirtilen matematiksel bir sabiti veya değeri temsil etmez.

Lokasyonlar: Birden fazla lokasyonda kullanılsa bile, hiçbir zaman değişmeyecek ve bu avantajı ihmal edecek.


1
Sihirli sayılar yerine sabitleri kullanmanın nedeni sadece sayılar değişeceğinden değil, aynı zamanda okunabilirlik ve öz dokümantasyon için.
Tulains Córdova

4
@ user61852: adlandırılmış sabitler her zaman daha okunaklı değildir. Sık sık, ama her zaman değil.
whatsisname,

2
Şahsen ben bu iki soruyu kullanıyorum: “Bu değer programın kullanım ömründe değişecek mi?” ve "Bu yazılım üzerinde çalışmayı umduğum geliştiriciler bu numaranın ne için olduğunu anlar mı?"
Steven Burnap

4
Y2K problemini mi kastediyorsun? Burada alakalı olduğundan emin değilim. Evet, 'tarih - 1900' gibi bir çok kod vardı, ancak bu kodda sorun "1900" sihirli rakamı değildi.
Steven Burnap

1
Bu cevap, 1024 kesinlikle bir tane olan bazı “açık” rakamların, birileri onlar için adlandırılmış bir sabit tanımladığında bile , diğer geliştiricilerin kendiliğinden rakamlar olarak yazma ihtimalinin çok yüksek olduğu şeklinde bir ifadeden faydalanabilir . Ben zaten bir tane olduğunu bilmiyorsam , 1024 bayt tutarında dönüşüm kullanmam gerekirse, 1024 için kaynak kodunu bulmayı düşünmemiştim .
Hyde

27

Bu alıntı

Sorun bu değil, sihir.

Jörg W tarafından söylendiği gibi Mittag bu soruyu oldukça iyi cevaplamaktadır.

Bazı sayılar sadece belli bir bağlamda büyülü değildir. Soruda verilen örnekte, ölçü birimleri değişken isimleriyle belirtilmiş ve gerçekleşen işlem oldukça açıktı.

Bu yüzden 1024büyülü değil çünkü bağlam, dönüşümler için kullanılacak uygun, sabit değer olduğunu açıkça ortaya koyuyor.

Aynı şekilde, bir örnek:

var numDays = numHours / 24; 

eşit derecede açık ve büyülü değil çünkü 24 saat içinde olduğu biliniyor.


21
Ama ... ama ... 24 değişebilir! Dünya rotasyonunu yavaşlatıyor ve sonunda 25 saat sürecek! (Tabii ki hepimiz o zamana kadar ölmüş olacağız, bu yazılımın başkasının problemine bakım

14
Yazılımınız Mars'ta dağıtıldıktan sonra ne olur ? Bu sabiti enjekte ediyor olmalısın ...
durron597 17:14

8
@ durron597: peki ya programınız o zaman dünyanın yavaşlaması için yeterince uzun çalışıyorsa . Bir sabit enjekte etmemelisiniz, bunun yerine bir zaman damgasını (şu anda varsayılan) kabul eden ve zaman damgasının düştüğü gündeki saat sayısını döndüren bir işlev değilsiniz ;-)
Steve Jessop

13
Ya YAGNI'yi öğrenmeniz gerekecek.
whatsisname,

3
@ durron597 Zaman tutma yazılımınız Mars'ta konuşlandırıldığında özel bir şey olmaz, çünkü kongre ile Mars günleri 24 saat, ancak her saat Dünya'dakilere göre% 2,7 daha uzundur . Tabii ki, ne bir Dünya sidereal günü ne de bir Dünya güneş günü tam olarak 24 saattir (tam olarak aynı sayfadadır), bu yüzden 24 yine de kullanamazsınız ! Izkata'nın bahsettiği gibi, sıçrama saniyeleri acıtıyor. Belki de 24Mars'taki sabiti kullanırken Dünya'da olduğundan daha iyi şanslarsınız !
CVn

16

Diğer posterler, dönüşümün gerçekleştiğinin 'açık' olduğunu belirtti, ancak ben aynı fikirde değilim. Bu noktada, asıl soru şunları içermektedir:

kilobayt kibibitler

Bu yüzden zaten yazarın karıştığını veya karıştığını biliyorum. Wikipedia sayfası karışıklığa ekler:

1000 = KB kilobyte (metric)
1024 = kB kilobyte (JEDEC)
1024 = KiB kibibyte (IEC)

Bu yüzden "Kilobayt" hem 1000 hem de 1024 faktörünü ifade etmek için kullanılabilir. Bunun üzerine, 1024 kilobayt (JEDEC) veya kibibit (IEC) anlamına gelebilir. Neden tüm bu karmaşayı açık bir şekilde sabit bir isimle parçalamıyorsunuz? BTW, bu konuyu sık sık "BYTES_PER_KBYTE" kullandı ve bu daha az belirsiz değil. KBYTE: KIBIBYTE veya KILOBYTE mı? Ben JEDEC görmezden ve izlenmesini tercih BYTES_PER_KILOBYTE = 1000ve BYTES_PER_KIBIBYTE = 1024. Daha fazla karışıklık yok.

İnsanların benden hoşlanmasının ve dışarıdaki birçok insanın nedeninin 'militan' olmalarına (burada bir yorumcuya alıntı yapmak için) sihirli sayıları isimlendirmekle ilgili düşünceleri tamamen yapmayı düşündüğünüzü belgelemek ve belirsizliği ortadan kaldırmakla ilgili. Ve aslında çok fazla kafa karışıklığına yol açan bir ünite seçtiniz.

Görürsem:

int BYTES_PER_KIBIBYTE = 1024;  
...  
var kibibytes = bytes / BYTES_PER_KIBIBYTE;  

O zaman yazarın ne yapmak istediği hemen bellidir ve belirsizlik yoktur. Sabiti birkaç saniye içinde kontrol edebilirim (başka bir dosyada olsa bile), bu yüzden 'anlık' olmasa da, anlık görüntüye yakın.

Sonunda, onu yazarken açıkça görülebilir, ancak daha sonra geri döndüğünüzde daha az belirgin olacak ve bir başkası düzenlediğinde daha az belirgin olabilir. Bir sabit yapmak için 10 saniye sürer; birimlerle ilgili bir hata ayıklamak yarım saat veya daha fazla sürebilir (kod size atlamayacak ve birimlerin yanlış olduğunu söylemeyecek, bunu anlamak için matematiği kendiniz yapmanız gerekecek, ve muhtemelen birimleri kontrol etmeden önce 10 farklı caddeyi avlayacaksınız).


2
İyi karşı cevap. Bireysel takım kültürünü hesaba katarsanız daha güçlü olur. Eğer iman ederse benim SE profili , ben bu belirli standartlar öncesine kadar yaşlıyım. Bu yüzden tek karışıklık "şu anki (standart dışı) standart terim nedir?" Ve aynı terminoloji (olmayan) güçlükleri olan bir dinozor arkadaşlarından oluşan bir ekiple çalıştığımı varsayma konusunda muhtemelen güvende olacaksınız.

@ GlenH7: IMHO, iki büyüklüğündeki parçaların gücüne tahsis edildiğinden, iki temelli birimin gücü depoda tutulmalıydı. Minimum ayırma boyutu 4096 bayttır, 256 minimum boyutlu dosyayı saklamak için gereken depolama miktarına veya 244.140625 bu tür dosyaları saklamak için gereken depolama miktarına sahip olmak daha mantıklı mıdır? Şahsen, sabit sürücü yapıcı megabaytlar ve diğer megabaytlar arasındaki farkı, televizyondaki diyagonal inç ve gerçek diyagonal inç arasındaki farka benzer buluyorum.
Süpermen

@Ryan: Bu özel durum için standart birimlerin benimsenmesi konusunda militan olmayı tercih ederim - KB 1000 byte veya kod yanlış, 1024 byte KiB veya kod yanlış. Bu, "birimler belirsiz" sorununu aşmamızın tek yolu. “Sihirli sabitleri” (gibi KB) farklı şekilde tanımlayan farklı insanlar yardımcı olmaz.
Brendan,

11

Bir adı sayısal bir değere atıfta bulunmak, bu adı kullanan bir yerde farklı bir değer gerektiğinde, muhtemelen tümünde gerekli olacağına işaret eder. Ayrıca, isme atanan sayısal değerin değiştirilmesinin, değeri değiştirmenin meşru bir yolu olduğu öne sürülmektedir. Böyle bir uygulama doğru olduğunda faydalı, yanlış olduğunda tehlikeli olabilir.

İki farklı yerin belirli bir gerçek değeri (örneğin, 1024) kullanması, bir programcının birini değiştirmesini isteyecek olan değişikliklerin, programcıya başkalarını değiştirmek isteme konusunda ilham vermesi muhtemel olduğunu, ancak bu uygulamanın uygulanacak olandan daha zayıf olduğunu göstermektedir. programcı böyle bir sabite isim atadıysa.

Bunun gibi önemli bir tehlike, #define BYTES_PER_KBYTE 1024karşılaşan birine printf("File size is %1.1fkB",size*(1.0/BYTES_PER_KBYTE));kodun binlerce bayt kullanması için güvenli bir yolun #defineifadeyi değiştirmek olacağına işaret etmesi olabilir . Ancak, böyle bir değişiklik, örneğin, başka bir ilgisiz kodun Kbytes içindeki bir nesnenin boyutunu alması ve bunun için bir tampon tahsis ederken bu sabiti kullanması halinde, felaket olabilir.

1024 sabiti tarafından sunulan her farklı amaç için farklı bir isim kullanmak #define BYTES_PER_KBYTE_FOR_USAGE_REPORT 1024ve bunları kullanmak makul olabilir #define BYTES_PER_KBYTE_REPORTED_BY_FNOBULATOR 1024ancak bu, birçok tanımlayıcının tam olarak bir kez tanımlanması ve kullanılmasıyla sonuçlanacaktır. Ayrıca, çoğu durumda, kullanıldığı yerde bir kodu görürse, bir değerin ne anlama geldiğini anlamak en kolay ve orada kullanılan herhangi bir sabitin değerlerini görürse, kodun nerede olduğunu bulmak en kolay yöntemdir. Sayısal bir hazır bilgi, belirli bir amaç için yalnızca bir kez kullanılırsa, hazır bilginin kullanıldığı yere yazılması, genellikle bir yere bir etiket atamak ve değerini başka bir yerde kullanmaktan daha anlaşılır bir kod verir.


7

Sadece sayıyı kullanmaya eğilmek isterdim, ancak önemli bir sorunun gündeme gelmediğini düşünüyorum: Aynı sayı farklı bağlamlarda farklı anlamlara gelebilir ve bu yeniden canlandırmayı zorlaştırabilir.

1024 aynı zamanda MiB başına KiB sayısıdır. Bu hesaplamayı bir yerde veya birden fazla yerde göstermek için 1024 kullandığımızı varsayalım ve şimdi bunun yerine GiB'yi hesaplamak için değiştirmemiz gerekiyor. Sabitin değiştirilmesi, bazı yerlerde yanlışlıkla yanlış olanı değiştirebileceğiniz veya başkalarında kaçırabileceğiniz global bir bulma / değiştirme işleminden daha kolaydır.

Ya da bir gün güncellenmesi gereken tembel bir programcı tarafından tanıtılan bir bit maskesi bile olabilir.

Bu, örnek olarak ele alınan bir örnek olmakla birlikte, bazı kod esaslarında bu, yeni gereksinimler için yeniden düzenleme veya güncelleme yaparken sorunlara neden olabilir. Bu özel durum için düz sayının gerçekten kötü bir form olduğunu düşünmüyorum, özellikle hesaplama işlemini yeniden kullanma yöntemine ekleyebilirseniz, muhtemelen kendim yaparım, ancak sabiti daha 'doğru' olarak düşünürdüm.

Yine de adlandırılmış sabitleri kullanırsanız, supercat'ın dediği gibi bağlamın da önemli olup olmadığını ve birden fazla ada ihtiyacınız olup olmadığını düşünmeniz önemlidir.

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.