İf (flag == 0) veya if (0 == flag) hangisi daha hızlı çalışacak?


111

Mülakat soru: Bir daha hızlı yürütmek, olur if (flag==0)ya if (0==flag)? Neden?


330
Şimdiye kadarki en aptalca röportaj sorusuna aday gösterildi. Ve sert bir rekabet var.
Konrad Rudolph

119
Siz: Bu ikisi arasındaki farkın muhtemelen uğraşmaya değer olabileceği bir durumu belirtin. Muhabir: Tamam, işe alındınız.
Chris Lutz

37
İkisi arasındaki tek fark, daha sonraki sözleşmeyle, if(flag = 0)biraz okunabilirlik fiyatıyla böceklere karşı sigortalı olmanızdır .
Amarghosh

22
@Amarghosh: Kodunuzun okunması zor ve sezgisel olmaması pahasına. İlkini derleyici uyarılarınızı açtığınızda kullanın, kazan-kazan.
GManNickG

129
Bir derleyici yazar röportajında ​​bunu anladı. O, cevaben fısıldadı "tek yapmak hangi sen daha hızlı olmak istiyorum?".

Yanıtlar:


236

Henüz doğru bir cevap görmedim (ve zaten bir miktar var) uyarı: Nawaz kullanıcı tanımlı tuzağa işaret etti . Ve "en aptal soru" üzerine aceleyle verdiğim oy için pişmanlık duyuyorum çünkü çoğu kişi bunu doğru anlamadı ve derleyici optimizasyonu hakkında güzel bir tartışma için yer veriyor gibi görünüyor :)

Cevap:

Nedir flagbireyin tipi?

flagGerçekte kullanıcı tanımlı bir tür olduğu durumda . Daha sonra hangi aşırı yükün operator==seçildiğine bağlıdır . Elbette simetrik olmayacakları aptalca görünebilir, ancak kesinlikle izin verilir ve başka suistimaller de gördüm.

Yerleşik flagise, her ikisi de aynı hızı almalıdır.

Gönderen Wikipedia makalesinin üzerinde x86, bir için bahse girerim Jxxiçin talimat ififadesi: belki JNZ(Jump Değil Zero ise) ya da bazı eşdeğeri.

Optimizasyonlar kapalıyken bile derleyicinin bu kadar bariz bir optimizasyonu kaçırdığından şüpheliyim. Bu, Gözetleme Deliği Optimizasyonunun tasarlandığı türden şeylerdir .

DÜZENLEME: Yeniden ortaya çıktı, bu yüzden biraz montaj ekleyelim (LLVM 2.7 IR)

int regular(int c) {
  if (c == 0) { return 0; }
  return 1;
}

int yoda(int c) {
  if (0 == c) { return 0; }
  return 1;
}

define i32 @regular(i32 %c) nounwind readnone {
entry:
  %not. = icmp ne i32 %c, 0                       ; <i1> [#uses=1]
  %.0 = zext i1 %not. to i32                      ; <i32> [#uses=1]
  ret i32 %.0
}

define i32 @yoda(i32 %c) nounwind readnone {
entry:
  %not. = icmp ne i32 %c, 0                       ; <i1> [#uses=1]
  %.0 = zext i1 %not. to i32                      ; <i32> [#uses=1]
  ret i32 %.0
}

IR'nin nasıl okunacağını bilmeseniz bile, bunun kendi kendini açıklayıcı olduğunu düşünüyorum.


4
@Matthieu: Henüz bir doğru cevap görmediğimi söyledin .. ama benimki doğru, sanırım: P
Nawaz

7
iyi! olası cevabınız "en aptal soruyu" "hilelere / en acımasızlara" çevirir. "hadi aday için bir çukur kazalım ve onun içine düşüp düşmediğini görelim ..." :) Sanırım hepimiz otomatik olarak flagbunun tamsayı veya boole olması gerektiğini varsayıyoruz . flagKullanıcı tanımlı türde bir değişkene sahip olan OTOH kendi başına oldukça yanlış, IMHO
davka

@Nawaz: Cevabınızın son paragrafını atlamış olabilirim: p
Matthieu M.

1
@Nawaz: Gerçekten yarışmıyorum, genellikle soruları cevaplandıktan sonra uzun süre okurum ve insanlar yalnızca en çok oy alan ilk cevapları okur :) Ama aslında derleyici optimizasyonları hakkında bir şeyler okuyorum ve bu beni çok etkiledi tipik bir önemsiz optimizasyon örneği, bu yüzden gerçekten rahatsız olan okuyucular için bunu belirteceğimi düşündüm ... Aslında çok fazla olumlu oy aldığım için oldukça şaşırdım. Şimdi, kesinlikle en çok çaba sarf ettiğim cevap olmamasına rağmen en çok oylanan cevabım: / Her neyse, cevabımı düzenledim ve ifademi düzelttim :)
Matthieu M.

2
@mr_eclair: yerleşik bir tür, dilde (adından da anlaşılacağı gibi) yerleşik olan bir türdür. Yani, tek bir #includeyönerge olmadan da kullanılabilir . Basitlik uğruna, genellikle tutarındaki int, char, boolve benzeri. Diğer tüm türleri onları beyan bazı kullanıcı sonucudur çünkü onların var olduğunu, kullanıcı tanımlı olduğu söylenen: typedef, enum, struct, class. Örneğin, std::stringkesinlikle kendiniz tanımlamamış olsanız bile kullanıcı tanımlıdır :)
Matthieu M.

56

GCC 4.1.2 ile amd64 için aynı kod:

        .loc 1 4 0  # int f = argc;
        movl    -20(%rbp), %eax
        movl    %eax, -4(%rbp)
        .loc 1 6 0 # if( f == 0 ) {
        cmpl    $0, -4(%rbp)
        jne     .L2
        .loc 1 7 0 # return 0;
        movl    $0, -36(%rbp)
        jmp     .L4
        .loc 1 8 0 # }
 .L2:
        .loc 1 10 0 # if( 0 == f ) {
        cmpl    $0, -4(%rbp)
        jne     .L5
        .loc 1 11 0 # return 1;
        movl    $1, -36(%rbp)
        jmp     .L4
        .loc 1 12 0 # }
 .L5:
        .loc 1 14 0 # return 2;
        movl    $2, -36(%rbp)
 .L4:
        movl    -36(%rbp), %eax
        .loc 1 15 0 # }
        leave
        ret

18
Derleyici optimizasyonunun aynı olduğunu kanıtlamak için fazladan mil gitmek için +1.
k rey

56

Sürümlerinizde hiçbir fark olmayacak.

typeBayrağının kullanıcı tanımlı bir tür olmadığını, bunun yerine yerleşik bir tür olduğunu varsayıyorum . Enum istisnadır! . Numaralamayı yerleşikmiş gibi ele alabilirsiniz. Aslında, değerleri yerleşik türlerden biridir!

Kullanıcı tanımlı tür ise (hariç enum), yanıt tamamen operatörü nasıl aşırı yüklediğinize bağlıdır ==. ==Sürümlerinizin her biri için bir tane olmak üzere iki işlev tanımlayarak aşırı yüklemeniz gerektiğini unutmayın !


8
Bu soruyu sormak için tek olası neden bu olabilir, IMHO
davka

15
Modern derleyiciler böylesine bariz bir optimizasyonu kaçırırsa çok şaşırırdım.
Pedro d'Aquino

3
Bildiğim kadarıyla! bit
tabanlı

8
@Nawaz: Olumsuz oy vermedim ama cevabınız gerçekte yanlış ve hala çok fazla olumlu oy alması korkunç. Kayıt için, bir tamsayıyı 0 ile karşılaştırmak tek bir montaj talimatıdır ve tamamen olumsuzla eşittir . Aslında, derleyici biraz aptalsa, bu olumsuzluktan bile hızlı olabilir (muhtemelen değil).
Konrad Rudolph

6
@Nawaz: Daha hızlı olabileceğini, olacağını veya olacağını söylemek hala yanlış. Eğer bir fark var olumsuzluk gerçekten iki operasyonlar çevirir beri, o zaman, daha hızlı olacaktır sürümü "sıfır karşı karşılaştırmak": "negate işlenen; sonuç sıfır ise onay olduğunu". Pratikte, elbette, derleyici onu düz "sıfırla karşılaştır" sürümüyle aynı kodu verecek şekilde optimize eder, ancak optimizasyon, onu yakalamak için olumsuz sürümüne uygulanır, tersi değil. Konrad haklı.
jalf

27

Kesinlikle hiçbir fark yok.

Atama / karşılaştırma yazım hatalarının ortadan kaldırılmasına atıfta bulunarak bu röportaj sorusunu yanıtlarken puan kazanabilirsiniz, ancak:

if (flag = 0)  // typo here
   {
   // code never executes
   }

if (0 = flag) // typo and syntactic error -> compiler complains
   {
   // ...
   }

Örneğin bir C-derleyicisinin eski ( flag = 0) durumunda uyarı verdiği doğru olsa da PHP, Perl veya Javascript veya <insert language here>.


@Matthieu Huh. Meta üzerindeki "uygun" destek stilini tanımlayan gönderiyi kaçırmış olmalıyım .
Linus Kleen

7
Hiç oy vermedim, ama bunun değeri nedir: İnsanların oy kullandıklarında kendilerini açıklamaları neden bu kadar önemli? Oylar tasarım gereği anonimdir. Olumsuz oy verenlerin her zaman yorum yapması gerektiği fikrine tamamen karşıyım, çünkü kişisel olarak, sırf bir soruna işaret eden bir yorum bıraktığım için kişisel olarak hiçbir zaman olumsuz seçmen olarak kabul edilmek istemiyorum. Belki de olumsuz oy veren, cevabın çoğunun hız sorusuyla alakasız olduğunu düşünüyordu? Belki de onaylamadığı bir kodlama stilini teşvik ettiğini düşündü? Belki de bir pislikti ve kendi cevabının en yüksek notu almasını istiyordu?
David Hedlund

3
İnsanlar, sebep ne olursa olsun istedikleri gibi özgürce oy kullanabilmelidir. İtibar açısından, bu neredeyse her zaman iyi bir şeydir, çünkü diğer insanları genellikle olumlu oy vermeye, hak edilmeyen olumsuz oylara karşı koymaya teşvik eder, aslında, tek bir olumlu oy beş haksız olumsuz oyu iptal eder.
David Hedlund

26
@David: Olumsuz oy verenler kendilerini açıklamalı çünkü bu site gizli popüler oy pusulaları, isimsiz oylama veya benzerleri hakkında değil. Bu site öğrenmekle ilgilidir. Birisi olumsuz oy vererek bir yanıtın yanlış olduğunu söylerse, olumsuz oy veren kişi nedenini açıklamazsa bilgisiyle bencil davranır. Haklı olduklarında tüm övgüyü almaya isteklidirler, ancak başkaları yanlış olduğunda bilgiyi paylaşmaya istekli değildirler.
John Dibling

1
Sadece canlandırıcı stil sorununu ortadan kaldırmak için, gerçekten Matthieu'nun bunu bir şaka olarak tasarladığını düşünüyorum. Bu tür konulara bağlı olarak herhangi birinin oy kullanması beni şaşırttı. Bunu söyledikten sonra, herkes oyları tamamen aynı şekilde kullanmıyor. Olumsuz oy vermenin mantığını görebiliyordum çünkü gönderi, seçmenlerin onaylamayabileceği bir kodlama stilini savunuyor gibi görünüyor ( kodlama stilini savunmak arasındaki farkı not edin - "kodunuzu böyle yazarsanız, yaptığınız zaman derleyici hatası alırsınız bu yazım hatası "- ve sadece parantez gibi bir kodlama stili kullanarak ) Bunun içinde ...
David Hedlund

16

Hız açısından kesinlikle bir fark olmayacak. Neden olmalı?


7
derleyici tamamen gecikmişse. Tek sebep bu.
JeremyP

@JeremyP: Derleyici gecikmiş olsa bile bir fark hayal edemiyorum. Derleyici yazar , söyleyebileceğim kadarıyla bunu kasıtlı olarak yapmak zorunda kalacaktı .
Jon

2
İşlemcinin "0 ise test et" talimatına sahip olduğunu varsayarsak, x == 0onu kullanabilir ancak 0 == xnormal bir karşılaştırma kullanabilir. Gecikmesi gerektiğini söylemiştim.
JeremyP

8
Bayrak, operatörün asimetrik aşırı yüklemesine sahip kullanıcı tanımlı bir
türse

Biz Çünkü belki sahip virtual operator==(int)bir kullanıcı tanımlı tür?
lorro

12

Flag, kullanıcı tanımlı bir tür olduğunda bir fark vardır

struct sInt
{
    sInt( int i ) : wrappedInt(i)
    {
        std::cout << "ctor called" << std::endl;
    }

    operator int()
    {
        std::cout << "operator int()" << std::endl;
        return wrappedInt;
    }

    bool operator==(int nComp)
    {
        std::cout << "bool operator==(int nComp)" << std::endl;
        return (nComp == wrappedInt);
    }

    int wrappedInt;
};

int 
_tmain(int argc, _TCHAR* argv[])
{
    sInt s(0);

    //in this case this will probably be faster
    if ( 0 == s )
    {
        std::cout << "equal" << std::endl;
    }

    if ( s == 0 )
    {
        std::cout << "equal" << std::endl;
    }
}

İlk durumda (0 == s) dönüştürme operatörü çağrılır ve sonra döndürülen sonuç 0 ile karşılaştırılır. İkinci durumda == operatörü çağrılır.


3
Bir dönüşüm operatörünün bir operatör == kadar alakalı olabileceğinden bahsetmek için +1.
Tony Delroy

11

Şüpheye düştüğünüzde, onu kıyaslayın ve gerçeği öğrenin.


2
kıyaslamada yanlış olan ne? bazen uygulama size teoriden daha fazlasını anlatıyor
Elzo Valugi

1
Bu konuyu okumaya başladığımda aradığım cevap buydu. Görünüşe göre teori pratikten daha çekici, cevaplara ve olumlu oylara bakıyorum :)
Samuel Rivas

röportajda nasıl kıyaslama yapabilirdi? artı bence görüşmeci, kıyaslamanın ne anlama geldiğini bile bilmiyor, bu yüzden gücenmiş olabilir.
IAdapter

Sorunun doğru yanıtı (IMO) "Bu, derleyiciye ve programın geri kalanına bağlıdır. Bir kıyaslama yazıp 5 dakika içinde test ederim"
Samuel Rivas

7

Hız açısından tam olarak aynı olmalılar.

Bununla birlikte, bazı kişilerin (eşitlik karşılaştırma operatörü) =yerine (atama operatörü) yazarsanız ortaya çıkabilecek tüm hataları önlemek için eşitlik karşılaştırmalarında ("Yoda koşullu" olarak adlandırılan) sabiti sola koymak için kullandığına dikkat edin ==; Birebir atama, bir derleme hatasını tetiklediğinden, bu tür bir hatadan kaçınılır.

if(flag=0) // <--- typo: = instead of ==; flag is now set to 0
{
    // this is never executed
}

if(0=flag) // <--- compiler error, cannot assign value to literal
{

}

Öte yandan, çoğu insan "Yoda koşullarını" tuhaf ve sinir bozucu buluyor, özellikle de önledikleri hata sınıfı yeterli derleyici uyarıları kullanılarak da tespit edilebildiği için.

if(flag=0) // <--- warning: assignment in conditional expression
{

}

Yankıladığınız için teşekkürler. Ancak, örneğin koşullu atamalarda PHP'nin uyarmayacağını unutmayın.
Linus Kleen

5

Başkalarının dediği gibi, hiçbir fark yok.

0değerlendirilmesi gerekiyor. flagdeğerlendirilmesi gerekiyor. Bu işlem, hangi tarafa yerleştirilirse yerleştirilsin aynı süreyi alır.

Doğru cevap şu olacaktır: ikisi de aynı hızda.

Hatta ifadeler if(flag==0)ve if(0==flag)aynı sayıda karaktere sahip! Bunlardan biri olarak yazıldıysa if(flag== 0), derleyicinin ayrıştırmak için fazladan bir boşluğu olur, bu nedenle derleme zamanını belirtmek için geçerli bir nedeniniz olur.

Ancak böyle bir şey olmadığı için, birinin diğerinden daha hızlı olması için kesinlikle hiçbir neden yoktur. Bir sebep varsa, derleyici kod oluşturmak için çok ama çok garip şeyler yapıyor demektir ...


5

Hangisinin hızlı olduğu == sürümünün hangi sürümünü kullandığınıza bağlıdır. Burada, 2 olası == uygulamasını kullanan ve x == 0 veya 0 == x aramayı seçip seçmediğinize bağlı olarak 2'den biri seçili olan bir pasaj.

Sadece bir POD kullanıyorsanız, hız söz konusu olduğunda bu gerçekten önemli olmamalı.

#include <iostream>
using namespace std;

class x { 
  public:
  bool operator==(int x) { cout << "hello\n"; return 0; }
  friend bool operator==(int x, const x& a) { cout << "world\n"; return 0; } 
};

int main()
{ 
   x x1;
   //int m = 0;
   int k = (x1 == 0);
   int j = (0 == x1);
}

5

Eh, alıştırma uğruna, OP'ye yapılan yorumlarda söylenenlerin hepsine tamamen katılıyorum:

Derleyici yeterince akıllı değilse (aslında onu kullanmamalısınız) veya optimizasyon devre dışı bırakılmışsa, sayısal değerlerin daha genel (ve maliyetli) bir karşılaştırması olurken x == 0yerel bir montaj jump if zerotalimatına derlenebilir 0 == x.

Yine de bu şekilde düşünen bir patron için çalışmak istemem ...


4

Uygulama hızları açısından kesinlikle bir fark yok. Her iki durumda da durumun aynı şekilde değerlendirilmesi gerekir.


3

Bence en iyi yanıt "bu örnek hangi dilde"?

Soru dili belirtmedi ve hem 'C' hem de 'C ++' olarak etiketlendi. Kesin bir cevap daha fazla bilgiye ihtiyaç duyar.

Bu çok kötü bir programlama sorusu, ancak "görüşülen kişiye kendini asması ya da bir ağaç salıncağı inşa etmesi için yeterince ip verelim" bölümünde iyi olabilir. Bu tür sorularla ilgili sorun, genellikle yazılmaları ve görüşmeciden görüşmeciye, tüm açılardan gerçekten anlamayan insanlara ulaşana kadar aktarılmasıdır.


3

Önerilen yolları kullanarak iki basit program oluşturun.

Kodları birleştirin. Meclise bakın ve yargılayabilirsiniz, ancak bir fark olduğundan şüpheliyim!

Görüşmeler her zamankinden daha düşük.


2

Bir kenara olarak (aslında herhangi bir iyi derleyicinin bu soruyu tartışmalı hale getireceğini düşünüyorum, çünkü optimize edeceğini düşünüyorum) 0 == flag over flag == 0 kullanmak = 'den birini unuttuğunuz yazım hatasını engeller (yani yanlışlıkla yazarsanız bayrak = 0 derlenecek, ancak 0 = bayrak olmayacak), ki bence herkesin bir noktada yaptığı bir hata ...


0

Bir fark varsa, derleyicinin bir kez daha hızlı olanı seçmesini ne durdurur? Yani mantıksal olarak, herhangi bir fark olamaz. Muhtemelen görüşmecinin beklediği budur. Aslında harika bir soru.

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.