For döngüsünde olduğu gibi tamsayılar kullanılırken <= ve> = kullanılmamalı mı? [kapalı]


15

Öğrencilerime eşit testin şamandıra değişkenleri için güvenilir olmadığını, tamsayılar için iyi olduğunu açıkladım. Kullandığım ders kitabı> ve <>> ve <= 'den daha kolay okunabileceğini söyledi. Bir dereceye kadar katılıyorum, ama For döngüsünde? Döngünün başlangıç ​​ve bitiş değerlerini belirtmesi daha açık değil mi?

Ders kitabı yazarının doğru olduğu bir şey mi eksik?

Başka bir örnek, Range testlerinde aşağıdaki gibidir:

eğer skor> 89 notu = 'A'
ise skor> 79 notu = 'B' ise ...

Neden sadece şunu söylemiyorsunuz: eğer skor> = 90?

loops 

11
Ne yazık ki, bu seçenekler arasında davranış açısından nesnel bir fark olmadığından, bu, insanların daha sezgisel olarak gördükleri hakkında bir görüş anketine karşılık gelir ve anketler, bunun gibi StackExchange siteleri için uygun değildir.
Ixrec

1
Önemli değil. Gerçekten mi.
Auberon

4
Aslında, bu nesnel olarak cevaplanabilir. Beklemede ...
Robert Harvey

9
@Ixrec Her zaman "en iyi uygulama" nın uygun bir konu olarak görülmemesini ilginç buluyorum. Kim kodunu geliştirmek veya kodunu daha okunaklı yapmak istemez? Eğer insanlar aynı fikirde olmazlarsa, hepimiz sorunun daha fazla yönünü öğreniriz ve hatta ... hatta ... zihnimizi değiştirebiliriz! Ugh, bunu söylemek çok zordu. Robert Harvey nesnel olarak cevaplayabileceğini söylüyor. Bu ilginç olacak.

1
@nocomprende Çoğunlukla "en iyi uygulama", dil hakkında nesnel gerçeklere dayanan yararlı tavsiyeleri ifade edebilen , ancak sıklıkla "en popüler görüş" (veya terimi kullanan herkesin görüşü) anlamına gelen son derece belirsiz ve aşırı kullanılan bir terim olduğu için gerçekte tüm seçenekler eşit derecede geçerli ve geçersizdir. Bu durumda, yalnızca Robert'in yaptığı gibi belirli döngü türlerine yanıtı kısıtlayarak ve soruyu tamamen cevaplamayan bir yorumda belirttiğiniz gibi nesnel bir tartışma yapabilirsiniz.
Ixrec

Yanıtlar:


36

Sıfır tabanlı dizilere sahip kıvırcık destekli programlama dillerinde , bunun forgibi döngüler yazmak gelenekseldir :

for (int i = 0; i < array.Length, i++) { }

Bu, dizideki tüm öğeleri geçer ve en yaygın durumdur. <=Veya kullanılmasını önler >=.

Bunun değişmesi gereken tek zaman, ilk veya son öğeyi atlamanız veya ters yönde geçmeniz veya farklı bir başlangıç ​​noktasından veya farklı bir bitiş noktasına geçmeniz gerektiğidir.

Koleksiyonlar için, yineleyicileri destekleyen dillerde, bunu görmek daha yaygındır:

foreach (var item in list) { }

Hangi karşılaştırmaları tamamen önler.

Kullanmak zaman konusunda bir sert ve hızlı kural arıyorsanız <=vs <, bir tane değil; niyetinizi en iyi ifade eden şeyi kullanın. Kodunuzu "daha az veya saatte 55 kilometreye eşit" kavramını ifade etmek gerekiyorsa o zaman söylemek gerekir <=, değil <.

Not aralıkları hakkındaki sorunuzu cevaplamak >= 90daha mantıklıdır, çünkü 90, 89 değil, gerçek sınır değeridir.


9
Karşılaştırmaları tamamen engellemez, sadece numaralandırıcı uygulamasına taşıyarak onları halının altına süpürür. : P
Mason Wheeler

2
Tabii ki, ama bu artık bir dizi üzerinden geçmiyor, değil mi?
Robert Harvey

4
Çünkü diziler böyle fordöngüler için en yaygın kullanım şeklidir. forBurada verdiğim döngü şekli, bir deneyim deneyimi olan herhangi bir geliştirici tarafından anında tanınabilir. Daha spesifik bir senaryoya dayanan daha spesifik bir cevap istiyorsanız, sorunuzu sorunuza eklemeniz gerekir.
Robert Harvey

3
"niyetinizi en iyi ifade ne kullanın" <- Bu!
Jasper N. Brouwer

3
@ JasperN.Brouwer Programın sıfırıncı yasası gibi. Tüm stil kuralları ve kodlama kuralları, yetkileri kodun netliği ile çeliştiğinde en utanç içinde çöküyor.
Iwillnotexist Idonotexist

16

Önemli değil.

Ama Tartışmanın iyiliği için, iki seçenek analiz edelim a > bvs a >= b.

Dayan! Bunlar eşdeğer değil!
Tamam, o zaman a >= b -1vs a > bya a > bvs a >= b +1.

Hm, a >bve a >= bdaha iyi hem görünüm a >= b - 1ve a >= b +1. Bunların hepsi 1neyse? Bu yüzden, >bunun yerine >=ya da tam tersi olmanın herhangi bir faydasının rastgele 1s eklemek ya da çıkarmak zorunda kalmadan ortadan kaldırıldığını iddia ediyorum .

Ama ya bir rakamsa? Daha iyi demek mi a > 7yoksa a >= 6? Bir saniye bekle. Sabit kodlanmış değişkenlere >karşı kullanmanın >=ve yoksaymanın daha iyi olup olmadığını ciddi bir şekilde mi tartışıyoruz ? Gerçekten olmadığı konusu tartışmalı hale Yani a > DAYS_OF_WEEKdaha iyidir a >= DAYS_OF_WEEK_MINUS_ONE... yoksa değil mi a > NUMBER_OF_LEGS_IN_INSECT_PLUS_ONEvs a >= NUMBER_OF_LEGS_IN_INSECT? Ve 1sadece bu sefer değişken isimlerinde s toplama / çıkarma işlemine geri dönüyoruz . Ya da eşik, limit, maksimum kullanmak en iyisi ise tartışmalıdır.

Ve genel bir kural yok gibi görünüyor: karşılaştırılana bağlı

Ama gerçekten, birisinin kodunda iyileştirilmesi gereken çok daha önemli şeyler ve hala istisnaları olan çok daha objektif ve makul yönergeler (örn. Satır başına X karakter sınırı) vardır.


1
Tamam, genel bir kural yok. (Ders kitabının neden genel bir kural olarak göründüğünü merak ediyorum, ama gitmesine izin verebilirim.) Kaçırdığım bir not olduğu konusunda yeni bir fikir birliği yok.

2
@nocomprende çünkü kodlama ve biçimlendirme standartları tamamen öznel ve oldukça çekişmeli. Çoğu zaman hiçbiri önemli değil, ama programcılar hala onlar üzerinde kutsal savaşlar yapıyorlar. (sadece özensiz kodun hatalara yol

1
Kodlama standartları hakkında çok çılgın tartışmalar gördüm ama bu sadece pastayı alabilir. Gerçekten Aptalca.
JimmyJames

@JimmyJames tartışma hakkında şudur >vs >=veya tartışılması konusunda tartışma >vs >=anlamlıdır? Her ne kadar bunu tartışmaktan kaçınmak en iyisi olsa da: p
Thanos Tintinidis 18:16

2
“Programlar insanlar tarafından ve yalnızca bilgisayarların yürütmesi için bu arada okunmalıdır” - Donald Knuth. Okumayı, anlamayı ve sürdürmeyi en kolay hale getiren stili kullanın.
16'da basit kullanıcı

7

Hesaplama kullanarak maliyet açısından bir fark yoktur <ya >kıyasla <=ya >=. Aynı derecede hızlı hesaplanır.

Ancak döngüler için çoğu 0'dan sayılır (çünkü birçok dil dizileri için 0 dizinleme kullanır). Yani bu dillerdeki kanonik döngü

for(int i = 0; i < length; i++){
   array[i] = //...
   //...
}

bunu bir ile yapmak <=, tek tek bir hatayı önlemek için bir yere -1 eklemenizi gerektirir

for(int i = 1; i <= length; i++){
   array[i-1] = //...
   //...
}

veya

for(int i = 0; i <= length-1; i++){
   array[i] = //...
   //...
}

Tabii ki dil 1 tabanlı indeksleme kullanıyorsa, sınırlayıcı koşul olarak <= kullanırsınız.

Anahtar, koşulda ifade edilen değerlerin problem tanımındaki değerlerdir. Okumak daha temiz

if(x >= 10 && x < 20){

} else if(x >= 20 && x < 30){

}

yarı açık aralık için

if(x >= 10 && x <= 19){

} else if(x >= 20 && x <= 29){

}

ve 19 ile 20 arasında olası bir değer olmadığını bilmek için matematik yapmalı


"Uzunluk" fikrini görüyorum, ama ya sadece bir yerden gelen ve bir başlangıç ​​değerinden bir bitiş değerine yineleme amaçlı değerleri kullanıyorsanız. Sınıf örneği 5'ten 10'a kadar İşaretleme yüzdesiydi. (Markup = 5; markup <= 10; markup ++) ... için söylemek daha net değil mi? Neden testine geçeyim : işaretleme <11 ?

6
@nocomprende, sorun açıklamanızdaki sınır değerleri 5 ve 10 ise, biraz değiştirilmiş bir değer yerine kodda açıkça belirtilmesi daha iyidir.
cırcır ucube

üst sınırı bir parametredir zaman @nocomprende doğru biçim daha açıktır: for(markup = 5; markup <= MAX_MARKUP; ++markup). Başka herhangi bir şey onu aşırı derecede karmaşık hale getirir.
Navin

1

Demek isterim ki,> veya> = kullanmanız gerekmiyor. Mesele, etkileyici kod yazmanıza izin veren her şeyi kullanmaktır.

Bir tane eklemeniz / çıkarmanız gerektiğini fark ederseniz, diğer operatörü kullanmayı düşünün. Alan adınızın iyi bir modeliyle başladığınızda iyi şeylerin olduğunu görüyorum. Sonra mantık kendini yazar.

bool IsSpeeding(int kilometersPerHour)
{
    const int speedLimit = 90;
    return kilometersPerHour > speedLimit;
}

Bu çok daha etkileyici

bool IsSpeeding(int kilometersPerHour)
{
    const int speedLimit = 90;
    return kilometersPerHour >= (speedLimit + 1);
}

Diğer durumlarda, diğer yol tercih edilir:

bool CanAfford(decimal price, decimal balance)
{
    return balance >= price;
}

Çok daha iyi

bool CanAfford(decimal price, decimal balance)
{
    const decimal epsilon = 0e-10m;
    return balance > (price - epsilon);
}

Lütfen "ilkel saplantıyı" affedin. Açıkçası burada sırasıyla bir Hız ve Para türü kullanmak istersiniz, ancak onları kısalık için atladım. Mesele şu: Daha özlü olan ve çözmek istediğiniz iş sorununa odaklanmanızı sağlayan sürümü kullanın.


2
Hız sınırı örneği kötü bir örnektir. 90 km / s'lik bir bölgede 90 km / s hıza çıkmak hız sayılmaz. Bir hız sınırı dahildir.
eidsonator

kesinlikle haklısın, beynim benim tarafımda. daha iyi bir örnek kullanmak için düzenlemekten çekinmeyin, umarım nokta tamamen kaybolmaz.
sara

0

Sorunuzda belirttiğiniz gibi, değişken değişkenler üzerinde eşitlik testi güvenilir değildir.

Aynı şey <=ve için de geçerlidir >=.

Ancak, tamsayı türleri için böyle bir güvenilirlik sorunu yoktur. Benim düşünceme göre, yazar hangisinin daha okunabilir olduğu konusundaki görüşünü ifade ediyordu .

Ona katılıp katılmadığınız elbette sizin fikrinizdir.


Bu, diğer yazarlar ve alandaki gri kıllar tarafından genel olarak düzenlenen bir görüş mü? Eğer sadece "Bir Muhabirin Görüşü" ise öğrencilere bunu söyleyebilirim. Aslında, var. Bu fikri daha önce hiç duymamıştım.

Yazarın cinsiyeti önemsiz, ama yine de cevabımı güncelledim. Çözdüğüm sorun için en doğal olanı seçmeyi <veya seçmeyi tercih ederim <=. Diğerlerinin de belirttiği gibi, bir FOR döngüsünde <C-tipi dillerde daha mantıklıdır. Lehte başka kullanım durumları vardır <=. Uygun olduğunda ve gerektiğinde elinizdeki tüm aletleri kullanın.
Dan Pichelman

Katılmıyorum. Orada olabilir tamsayı türleri ile güvenilirlik sorunları be: C, düşünün: for (unsigned int i = n; i >= 0; i--)ya for (unsigned int i = x; i <= y; i++)eğer yolur UINT_MAX. Hata! Sonsuza dek döngüler.
jamesdlin

-1

İlişkilerin her <, <=, >=, >ve ayrıca == ve !=iki kayan nokta değerleri karşılaştırmak için kullanımları-vaka var. Her birinin belirli bir anlamı vardır ve uygun olanı seçilmelidir.

Her biri için tam olarak bu operatörü istediğiniz durumlar için örnekler vereceğim. (Yine de NaN'ların farkında olun.)

  • fGirdi olarak kayan nokta değeri alan pahalı bir saf fonksiyonunuz var. Senin hesaplamaları hızlandırmak için, sen, bir arama tablosu haritalama olan en son hesaplanan değerlerin bir önbellek, eklemeye karar xiçin f(x). ==Argümanları karşılaştırmak için gerçekten kullanmak isteyeceksiniz .
  • Bir sayıya anlamlı bir şekilde bölüp bölemeyeceğinizi bilmek ister misiniz x? Muhtemelen kullanmak istiyorsunuz x != 0.0.
  • xBirim aralığında bir değerin olup olmadığını bilmek ister misiniz? (x >= 0.0) && (x < 1.0)doğru durumdur.
  • dBir matrisin determinantını hesapladınız ve pozitif kesin olup olmadığını söylemek mi istiyorsunuz? Başka bir şey kullanmak için bir sebep yok d > 0.0.
  • Σ n = 1,…, ∞ n −α'nın ayrılıp ayrılmadığını bilmek ister misiniz? Test ederdim alpha <= 1.0.

Kayan nokta matematiği (genel olarak) tam değildir. Ancak bu, ondan korkmanız, sihir olarak muamele etmeniz ve kesinlikle içerdeyse iki kayan nokta miktarına eşit davranmamanız gerektiği anlamına gelmez 1.0E-10. Bunu yapmak gerçekten matematiğinizi kıracak ve tüm garip şeylerin olmasına neden olacaktır.

  • Örneğin, yukarıda belirtilen önbellek ile bulanık karşılaştırma kullanırsanız, komik hatalar ortaya koyacaksınız. Ama daha da kötüsü, işlev artık saf olmayacak ve hata daha önce hesaplanan sonuçlara bağlı olacak!
  • Evet, x != 0.0ve ysınırlı bir kayan nokta değeri olsa bile , sonlu y / xolması gerekmez. Ancak y / xtaşma veya işlemin başlangıçta matematiksel olarak iyi tanımlanmadığı için sonlu olup olmadığını bilmek uygun olabilir .
  • Bir girdi parametresinin x[0, 1) birim aralığında olması gereken bir önkoşulu olan bir fonksiyonunuz varsa, x == 0.0veya ile çağrıldığında bir onaylama hatası tetiklediğinde gerçekten üzülürüm x == 1.0 - 1.0E-14.
  • Hesapladığınız determinant doğru olmayabilir. Ancak, hesaplanan determinant olduğunda matrisin pozitif kesin olmadığını iddia edecekseniz 1.0E-30, hiçbir şey kazanılmaz. Tek yaptığınız yanlış cevap verme olasılığını arttırmaktı .
  • Evet, argümanınız alphayuvarlama hatalarından etkilenebilir ve bu nedenle alpha <= 1.0ifadenin gerçek matematiksel değeri alphahesaplanmış olsa bile doğru olabilir. 1'den büyük olabilir. Ancak bu noktada bu konuda yapabileceğiniz hiçbir şey yoktur.

Yazılım mühendisliğinde her zaman olduğu gibi, hataları uygun seviyede ele alın ve sadece bir kez ele alın. Eğer 1.0E-10kayan nokta miktarlarını her karşılaştırdığınızda (bu çoğu insanın kullandığı sihirli değer gibi görünüyor, nedenini bilmiyorum) sırasına yuvarlama hataları eklerseniz , yakında 1.0E+10...


1
En mükemmel cevap, kuşkusuz, sadece sorulandan farklı bir soru için.
Dewi Morgan

-2

Bir döngüde kullanılan koşullu tür, bir derleyicinin daha iyi veya daha kötü şekilde gerçekleştirebileceği optimizasyon türlerini sınırlayabilir. Örneğin, verilenler:

uint16_t n = ...;
for (uint16_t i=1; i<=n; i++)
  ...  [loop doesn't modify i]

Bir derleyici yukarıdaki durum n'inci geçiş döngü sonra çıkmak için döngüye neden gerektiğini varsayalım olabilir sürece n kudretini 65535 ve ben n aşarak dışında bazı moda döngü kudreti çıkışında. Bu koşullar geçerliyse, derleyici, yukarıdaki koşuldan başka bir şey çıkmasına neden olana kadar döngünün çalışmasına neden olacak kod üretmelidir.

Bunun yerine döngü şöyle yazıldıysa:

uint16_t n = ...;
for (uint16_t ctr=0; ctr<n; ctr++)
{
  uint16_t i = ctr+1;
  ... [loop doesn't modify ctr]
}

bir derleyici, döngünün hiçbir zaman n'den fazla yürütme gerektirmeyeceğini güvenli bir şekilde varsayabilir ve böylece daha verimli kod üretebilir.

İmzalı türlerle herhangi bir taşmanın kötü sonuçlar doğurabileceğini unutmayın. Verilen:

int total=0;
int start,lim,mult; // Initialize values somehow...
for (int i=start; i<=lim; i++)
  total+=i*mult;

Bir derleyici bunu şöyle yeniden yazabilir:

int total=0;
int start,lim,mult; // Initialize values somehow...
int loop_top = lim*mult;
for (int i=start; i<=loop_top; i+=mult)
  total+=i;

Hesaplamalarda taşma olmazsa böyle bir döngü orijinaliyle aynı şekilde davranır, ancak tamsayı taşmasının normalde tutarlı sarma semantiğine sahip olacağı donanım platformlarında bile sonsuza kadar çalışabilir.


Evet, sanırım bu ders kitabında biraz daha uzakta. Henüz düşünülmedi. Derleyici Optimizasyonları anlamak yararlıdır ve taşmadan kaçınılmalıdır, ancak sorumun asıl motivasyonu değildi, bu daha çok insanların kodu nasıl anladığıyla ilgilidir. X> 5 veya x> = 6 okumak daha mı kolay? Şey, o bağlıdır ...

Bir Arduino için yazmıyorsanız, int için maksimum değer 65535'ten biraz daha yüksek olacaktır.
Corey

1
@Corey: uint16_t için maksimum değer, türün bulunduğu herhangi bir platformda 65535 olacaktır; İlk örnekte uint16_t kullandım çünkü bir uint16_t'ın tam maksimum değerini bir uint32_t'den daha fazla bilmesini beklerdim. Her iki durumda da aynı husus geçerlidir. İkinci örnek, "int" türüyle ilgili agnostiktir ve birçok insanın modern derleyiciler hakkında tanımadığı kritik bir davranışsal noktayı temsil eder.
Supercat
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.