X + = a, x = x + a'dan daha mı hızlıdır?


84

Stroustrup'un "C ++ Programlama Dili" ni okuyordum, burada bir değişkene bir şey eklemenin iki yolundan biri olduğunu söylüyor

x = x + a;

ve

x += a;

Tercih ediyor +=çünkü büyük olasılıkla daha iyi uygulanıyor. Sanırım o da daha hızlı çalıştığını söylüyor.
Ama gerçekten öyle mi? Derleyiciye ve diğer şeylere bağlıysa, nasıl kontrol ederim?


45
"C ++ Programlama Dili" ilk olarak 1985 yılında yayınlandı. En son sürüm 1997'de yayınlandı ve 1997 sürümünün özel bir baskısı 2000'de yayınlandı. Sonuç olarak, bazı bölümler büyük ölçüde güncelliğini yitirdi.
JoeG

5
İki çizgi potansiyel olarak tamamen farklı bir şey yapabilir. Daha spesifik olmalısın.
Kerrek SB


26
Modern derleyiciler, bu soruların "modası geçmiş" olarak kabul edilmesi için yeterince akıllıdır.
gd1

2
Yinelenen soru C ++ değil C'yi sorduğu için bunu yeniden açtı.
Kev

Yanıtlar:


212

Tuzuna değer herhangi bir derleyici, herhangi bir yerleşik tür için her iki yapı için de tam olarak aynı makine dili sırasını üretecektir ( int,float uzun deyimi gerçekten olarak basit olarak olduğu kadar, vs) x = x + a; ve optimizasyon etkindir . (Özellikle, -O0varsayılan mod olan GCC'ler anti-optimizasyonlar gerçekleştirir hata ayıklayıcıların her zaman değişken değerleri bulabilmesini sağlamak için belleğe tamamen gereksiz depolar eklemek gibi .)

İfade daha karmaşıksa, farklı olabilirler. fBir işaretçi döndüren bir işlev olduğunu varsayalım , sonra

*f() += a;

fyalnızca bir kez arar , oysa

*f() = *f() + a;

iki kere arar. fYan etkileri varsa , ikisinden biri yanlış olacaktır (muhtemelen ikincisi). fYan etkileri olmasa bile , derleyici ikinci çağrıyı ortadan kaldıramayabilir, bu nedenle ikincisi gerçekten daha yavaş olabilir.

Ve burada C ++ hakkında konuştuğumuz için, aşırı yüklenen sınıf türleri için durum tamamen farklıdır operator+ve operator+=. Eğer xoptimizasyonu önce - - o zaman böyle bir türüdür x += açevirir

x.operator+=(a);

oysa x = x + açevirir

auto TEMP(x.operator+(a));
x.operator=(TEMP);

Şimdi, eğer sınıf düzgün bir şekilde yazılmışsa ve derleyicinin optimize edicisi yeterince iyiyse, her ikisi de aynı makine dilini üretecek, ancak yerleşik tipler için olduğu gibi kesin bir şey değil. Bu muhtemelen Stroustrup'un kullanımını teşvik ettiğinde düşündüğü şeydir +=.


14
Başka bir yönü daha var - okunabilirlik . Eklemek için C ++ deyim expriçin varolduğunu var+=exprve ona okuyucuların karıştıracaktır başka bir yol yazma.
Tadeusz Kopec

21
Kendinizi yazarken *f() = *f() + a;bulursanız, gerçekten neyi başarmaya çalıştığınıza
Adam Davis

3
Ve var = var + ifade kafanızı karıştırıyorsa, ancak var + = ifade etmiyorsa, şimdiye kadar tanıştığım en tuhaf yazılım mühendisisiniz. Her ikisi de okunabilir; sadece tutarlı olduğunuzdan emin olun (ve hepimiz op = kullanıyoruz, bu yüzden yine de tartışmalı = P)
WhozCraig

7
@PiotrDobrogost: Soruları yanıtlamanın nesi yanlış? Her durumda, kopyaları kontrol eden soru soran kişi olmalıdır.
Gorpik

4
@PiotrDobrogost bana biraz ... kıskanıyormuşsun gibi geliyor ... Eğer kopyaları aramak için dolaşmak istiyorsan, git. Ben, ben, tekrarı aramaktansa soruları cevaplamayı tercih ederim (daha önce gördüğüm özellikle hatırladığım bir soru değilse). Bazen daha hızlı olabilir ve soruyu daha hızlı soran kişiye yardımcı olabilir. Ayrıca, bunun bir döngü olmadığını unutmayın. 1sabittir, auçucu, kullanıcı tanımlı bir tür veya her neyse olabilir. Tamamen farklı. Aslında bunun nasıl kapandığını bile anlamıyorum.
Luchian Grigore

56

Aynı olacak olan sökme işlemine bakarak kontrol edebilirsiniz.

Temel türler için her ikisi de eşit derecede hızlıdır.

Bu, bir hata ayıklama derlemesi tarafından üretilen çıktıdır (yani optimizasyon yapılmaz):

    a += x;
010813BC  mov         eax,dword ptr [a]  
010813BF  add         eax,dword ptr [x]  
010813C2  mov         dword ptr [a],eax  
    a = a + x;
010813C5  mov         eax,dword ptr [a]  
010813C8  add         eax,dword ptr [x]  
010813CB  mov         dword ptr [a],eax  

Aşırı yükleyebileceğiniz kullanıcı tanımlı türler içinoperator + ve operator +=bunların ilgili uygulamalarına bağlıdır.


1
Her durumda doğru değil. Bir hafıza adresini bir kasaya yüklemenin, arttırmanın ve geri yazmanın, hafıza konumunu doğrudan arttırmaktan (atomik kullanmadan) daha hızlı olabileceğini buldum. Kodu hışırdatmayı deneyeceğim ...
James

Kullanıcı tanımlı türler nasıl? İyi derleyiciler gerektiğini eşdeğer takımını oluşturmak, ancak böyle bir garantisi yoktur.
mfontanini

1
@LuchianGrigore Hayır, a1 xise volatileve derleyici oluşturabilirse inc DWORD PTR [x]. Bu yavaş.
James

1
@Chiffa derleyiciye bağlı değildir, ancak geliştiriciye bağlıdır. Sen uygulamak olabilir operator +hiçbir şey yapmamak ve operator +=100000 asal sayı hesaplamak ve sonra geri dönmek için. Tabii ki, bu aptalca bir şey olurdu, ama mümkün.
Luchian Grigore

3
@James: Programınız arasındaki performans farkı mantıklı olup olmadığını ++xve temp = x + 1; x = temp;büyük olasılıkla o ++ montaj yerine c değerinden yazılmalıdır sonra ...
EmirCalabuch

11

Evet! xYan etkileri olabilecek durumda, ikincisi için yazmak, okumak daha hızlı ve anlamak daha hızlıdır . Yani genel olarak insanlar için daha hızlı. Genel olarak insan zamanı, bilgisayar zamanından çok daha pahalı, bu yüzden sorduğunuz şey bu olmalı. Sağ?


8

Bu gerçekten x ve a türüne ve + uygulamasına bağlıdır. İçin

   T x, a;
   ....
   x = x + a;

derleyicinin x + a değerini içerecek geçici bir T oluşturması gerekirken, onu değerlendirir ve bunu daha sonra x'e atayabilir. (Bu işlem sırasında x veya a'yı çalışma alanı olarak kullanamaz).

X + = a için geçici olması gerekmez.

Önemsiz tipler için hiçbir fark yoktur.


8

Aradaki fark x = x + ave x += amakinenin geçmesi gereken iş miktarıdır - bazı derleyiciler bunu optimize edebilir (ve genellikle yapar), ancak genellikle, optimizasyonu bir süre göz ardı edersek, eski kod parçacığında şu olur: makinenin değeri xiki kez araması gerekirken, ikincisinde bu aramanın yalnızca bir kez yapılması gerekir.

Bununla birlikte, bahsettiğim gibi, bugün çoğu derleyici, talimatı analiz edecek ve ortaya çıkan makine talimatlarını azaltacak kadar zekidir.

Not: Stack Overflow'da ilk cevap!


6

Bu C ++ 'yı etiketlediğiniz gibi, gönderdiğiniz iki ifadeden öğrenmenin bir yolu yoktur. 'X'in ne olduğunu bilmeniz gerekir (bu biraz' 42 'cevabına benzer). Eğer xbir POD ise, o zaman gerçekten çok fark yaratmak için gitmiyor. Bununla birlikte, xbir sınıf ise , çok farklı yürütme sürelerine yol açan farklı davranışlara sahip olabilecek operator +ve operator +=yöntemleri için aşırı yükler olabilir.


6

+=Derleyici için hayatı çok daha kolaylaştırdığınızı söylerseniz . Tanımasını derleyici için Amacıyla x = x+aaynıdır x += aderleyici zorundadır

  • Sol tarafın ( x) yan etkisi olmadığından ve her zaman aynı l-değerine atıfta bulunduğundan emin olmak için analiz edin . Örneğin, bu olabilir z[i]ve emin de o yapmak zorundadır zve ideğişmez.

  • sağ tarafı ( x+a) analiz edin ve bunun bir özet olduğundan ve sol tarafın, olduğu gibi dönüştürülebilmesine rağmen sağ tarafta bir kez ve yalnızca bir kez oluştuğundan emin olun z[i] = a + *(z+2*0+i).

Ne demek eklemek ise ahiç xsen ne kastettiğini açıkça derken, derleyici yazar bunu takdir eder. Bu şekilde, derleyicinin yazarının tüm hataları ortadan kaldırmayı umduğu kısmını kullanmazsınız ve bu, gerçekten kafanızı dışarı çıkaramadığınız sürece hayatı sizin için daha kolay hale getirmez . Fortran modu.


5

Somut bir örnek için, basit bir karmaşık sayı türü hayal edin:

struct complex {
    double x, y;
    complex(double _x, double _y) : x(_x), y(_y) { }
    complex& operator +=(const complex& b) {
        x += b.x;
        y += b.y;
        return *this;
    }
    complex operator +(const complex& b) {
        complex result(x+b.x, y+b.y);
        return result;
    }
    /* trivial assignment operator */
}

A = a + b durumu için, fazladan bir geçici değişken oluşturmalı ve sonra onu kopyalamalıdır.


Bu çok güzel bir örnek, 2 operatörün nasıl uygulandığını gösteriyor.
Grijesh Chauhan

5

Yanlış soruyu soruyorsun.

Bunun bir uygulamanın veya özelliğin performansını artırması olası değildir. Öyle olsa bile, öğrenmenin yolu kodun profilini çıkarmak ve sizi nasıl etkilediğini kesin olarak bilmektir. Hangisinin daha hızlı olduğu konusunda endişelenmek yerine, netlik, doğruluk ve okunabilirlik açısından düşünmek çok daha önemlidir .

Bu, özellikle önemli bir performans faktörü olsa bile, derleyicilerin zaman içinde geliştiğini düşündüğünüzde bu özellikle doğrudur. Birisi yeni bir optimizasyon bulabilir ve bugün doğru cevap yarın yanlış olabilir. Klasik bir erken optimizasyon durumu.

Bu, performansın hiç önemli olmadığı anlamına gelmez ... Sadece mükemmel hedeflerinize ulaşmak için yanlış bir yaklaşım olduğu anlamına gelir. Doğru yaklaşım, kodunuzun gerçekten zamanını nerede geçirdiğini ve dolayısıyla çabalarınızı nereye odaklayacağınızı öğrenmek için profil oluşturma araçlarını kullanmaktır.


Kabul edildi, ancak bu düşük seviyeli bir soru olarak düşünülüyordu, büyük bir resim değil "Böyle bir farkı ne zaman düşünmeliyim".
Chiffa

1
OP'nin sorusu, diğerlerinin cevaplarında (ve olumlu oylarında) gösterildiği gibi tamamen meşruydu. Ne demek istediğini anlasak da (önce profil, vs.) bu tür şeyleri bilmek kesinlikle ilginç - gerçekten yazdığın her önemsiz ifadenin profilini çıkaracak mısın, aldığın her kararın sonucunun profilini çıkaracak mısın? SO'da halihazırda çalışmış, profilini çıkarmış, vakayı parçalarına ayırmış ve verecek genel bir cevabı olan insanlar varken bile?

4

Bunun makineye ve mimarisine bağlı olması gerektiğini düşünüyorum. Mimarisi dolaylı bellek adreslemeye izin veriyorsa, derleyici yazıcısı bunun yerine bu kodu kullanabilir (optimizasyon için):

mov $[y],$ACC

iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"

Oysa i = i + yşu dile çevrilebilir (optimizasyon olmadan):

mov $[i],$ACC

mov $[y],$B 

iadd $ACC,$B

mov $B,[i]


Bununla birlikte, iişaretçi döndüren bir işlev olup olmadığı gibi diğer komplikasyonlar da düşünülmelidir. GCC de dahil olmak üzere çoğu üretim seviyesi derleyicisi her iki ifade için de aynı kodu üretir (eğer tamsayılarsa).


2

Hayır, her iki yol da aynı şekilde ele alınır.


10
Aşırı yüklenmiş operatörleri olan kullanıcı tanımlı bir tür değilse.
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.