1 <10 karşılaştırması 1 <1000000'den daha mı ucuz?


65

Ben sadece ~ 1 milyar z-indexCSS için bir sayı olarak kullandım ve devam etmesi gereken karşılaştırmalar hakkında düşünüyordum. Çok büyük sayılarla çok küçük sayılar arasındaki karşılaştırmalarda ALU düzeyinde performans açısından bir fark var mı?

Örneğin, bu iki snippet'ten biri diğerinden daha pahalı mı olurdu?

snippet 1

for (int i = 0; i < 10000000; i++){
    if (i < 10000000000000) {
        //do nothing
    }
}

snippet 2

for (int i = 0; i < 10000000; i++){
    if (i < 1000) {
        //do nothing
    }
}


12
OP, dallanmanın ne kadar zaman alacağını sormuyor. Açıkçası, örneğin her iki parçacıkta da aynı zaman almasını sağlaması amaçlanmıştır. Soru, bireysel CMPmakinenin talimatının daha ibüyük olması durumunda daha yavaş olup olmayacağı ile ilgilidir .
Kilian Foth

18
Bu, CSS'de yapıldığından, bir dizgenin bir tamsayıya dönüştürülmesi, çalıştırma için harcanan zaman açısından karşılaştırma işleminin kendisine hakim olacaktır.

58
1000000000’yi bir CSS dosyasında z dizini olarak kullanmanız gerekirse, yanlış bir şey yaptınız.
Bergi

6
CSS için, metni bir tamsayıya dönüştürmenin ek yükü, dönüştürülecek sayı sayısına bağlı olacaktır (burada 1000000 gibi bir 6 basamaklı sayı, 1 gibi 1 basamaklı bir sayı kadar yaklaşık 6 kat daha pahalı olabilir); ve bu ek yük, tamsayı karşılaştırmalarının ek yükünden daha büyük büyüklüklerde olabilir.
Brendan,

Yanıtlar:


82

Çalıştığım her işlemci, işlenenlerden birini diğerinden çıkartarak, sonucu atarak ve işlemcinin bayraklarını (sıfır, negatif vb.) Tek başına bırakarak karşılaştırma yapar. Çıkarma tek bir işlem olarak yapıldığından, işlenenlerin içeriği önemli değil.

Soruyu kesin olarak yanıtlamanın en iyi yolu, kodunuzu montaj için derlemektir ve oluşturulan talimatlar için hedef işlemcinin belgelerine bakın. Mevcut Intel CPU'ları için bu Intel 64 ve IA-32 Architectures Yazılım Geliştirici El Kitabı olacaktır .

Açıklaması CMP( "karşılaştırma") talimat hacmi 2A, sayfa 3-126 veya PDF sayfa 618 olduğunu ve olarak çalışmasını anlatır:

temp ← SRC1 − SignExtend(SRC2);
ModifyStatusFlags; (* Modify status flags in the same manner as the SUB instruction*)

Bu, ikinci işlenenin gerekli olduğunda işaret uzatması, ilk işlenenden çıkarılması ve sonucun işlemcideki geçici bir alana yerleştirilmesi anlamına gelir. Ardından durum bayrakları SUB("çıkarma") komutunda (PDF'nin 1492. sayfasındaki) ayarlandığı gibi ayarlanır .

Orada hiçbir söz var CMPya SUBİşlenenlerin değerleri gecikme alakalı olması belgeler, kullandığınız herhangi bir değer güvenlidir.


5
Ya sayı 32-bit aritmetik için çok büyük olursa? Daha sonra yavaş hesaplamaya bölünmüş olmaz mıydı?
Falco

3
@Falco 64-bit ALU olan bir işlemcide değil (bu günlerde yerleşik alan dışında hemen hemen hepsi).
reirab

8
@Falco: Evet, ancak soru ALU performansı hakkında soru sorduğundan, ima edilen değerler CPU'nun kelime boyutuna veya sahip olabileceği herhangi bir SIMD komutunun yeteneklerine uygun olduğu anlamına gelir. Bundan daha büyük sayılarla çalışmak, CPU dışında birden fazla talimatla uygulanmalıdır. Bu 30 yıl önce, çalışmak için 8- veya 16 bitlik kayıtların olduğu zaman çok yaygındı.
Blrfl

6
@Falco Bu nasıl hata ayıklama gerektirir? Bu bir hata değil; 64 bit op'ları yerel olarak desteklemeyen bir CPU'da 64 bit op'lar yapmak biraz daha yavaş. Hiç kimsenin asla 2 ^ 31-1'in üzerinde bir sayı kullanmamasını önermek biraz saçma görünüyor.
reirab

2
@Falco Bunu söylediğine göre, tarayıcılardaki görüntü oluşturma motorları z-endekslerini temsil etmek için tamsayılar kullanıyor mu? Çoğu oluşturma motoru, aşina olduğum her şey için tek duyarlıklı yüzdürmeyi kullanırım (son rasterleştirme aşamasına kadar), ancak tarayıcı oluşturma motorları üzerinde çalışmamıştım.
reirab,

25

Çok büyük sayılarla çok küçük sayılar arasındaki karşılaştırmalarda ALU düzeyinde performans açısından bir fark var mı?

Çok sayıda küçük numaradan gidiyor sayısal türünü değiştirir sürece, pek olası değil, bir gelen söylemek intbir etmek long. O zaman bile, fark önemli olmayabilir. Programlama diliniz sessizce kapakların altında isteğe bağlı hassas aritmetik geçiş yaparsa, bir fark görmeniz daha olasıdır .

Bununla birlikte, kendi derleyiciniz farkında olmadığınız bazı akıllı optimizasyonlar yapıyor olabilir. Öğrendiğiniz yol ölçmektir. Kodunuzda bir profil oluşturucu çalıştırın; hangi karşılaştırmaların en uzun sürdüğünü görün. Ya da sadece bir zamanlayıcı başlatmak ve durdurmak.


Sorudaki önerilen sayıların, tipik bir 32-bit tamsayı tipinde farklı nümerik tipte olduğu belirtilmelidir ...
Falco

19

Pek çok işlemcinin, hemen belirtilen belirli işleçlerde, karşılaştırmalar dahil olmak üzere, aritmetik işlemleri gerçekleştirebilen "küçük" komutları vardır. Bu özel değerler dışındaki işlenenler ya daha geniş bir talimat formatı kullanmalı ya da bazı durumlarda "bellekten yük değeri" talimatını kullanmalıdır. ARM Cortex-M3 komut setinde, örneğin, bir değerin bir sabitle karşılaştırılabileceği en az beş yol vardır:

    cmp r0,#1      ; One-word instruction, limited to values 0-255

    cmp r0,#1000   ; Two-word instruction, limited to values 0-255 times a power of 2

    cmn r0,#1000   ; Equivalent to comparing value with -1000
                   ; Two-word instruction, limited to values 0-255 times a power of 2

    mov r1,#30000  ; Two words; can handle any value 0-65535
    cmp r0,r1      ; Could use cmn to compare to values -1 to -65535

    ldr r1,[constant1000000] ; One or two words, based upon how nearby the constant is
    cmp r0,r1
    ...

constant1000000:
    dd  1000000

İlk biçim en küçük olandır; ikinci ve üçüncü form, kodun alındığı hafızanın hızına bağlı olarak hızlı bir şekilde uygulanabilir veya çalışmayabilir. Dördüncü form neredeyse kesinlikle ilk üçten daha yavaştır ve beşinci form daha da yavaş olacaktır, ancak ikincisi herhangi bir 32-bit değerinde kullanılabilir.

Eski x86 işlemcilerinde, kısa form karşılaştırma talimatları, uzun formdakilerden daha hızlı çalıştırılır, ancak birçok yeni işlemci, ilk getirildiklerinde hem uzun hem de kısa formları aynı temsile dönüştürür ve önbellekteki tek biçimli gösterimi saklar. Bu nedenle, yerleşik denetleyiciler (birçok mobil platformda bulunanlar gibi) hız farkına sahip olurken, x86 tabanlı çoğu bilgisayar olmaz.

Ayrıca, bir döngünün içinde bir sabitin yoğun olarak kullanıldığı birçok durumda, bir derleyicinin sabiti sadece bir kez - döngü başlamadan önce - zamanlama farklılıkları oluşturmada bir yükleyiciye yüklemesi gerekeceğini unutmayın. Öte yandan, küçük döngülerde bile, bunun her zaman olmayacağı bazı durumlar vardır; eğer bir ilmek küçük fakat yoğun bir şekilde yürütülürse, zaman zaman kısa anlık değerleri içeren ve uzun olanları içeren karşılaştırmalar arasında büyük bir performans olabilir.


MIPS'de yalnızca 16 bitlik bir anında kullanılabilir, bu nedenle kesinlikle 1 ile karşılaştırma 1000000'den daha kısa ve (muhtemelen) daha hızlı olacaktır. Belki Sparc ve PowerPC ile aynıdır. Ve bazı kaynaklardan, Intel’in de bazı durumlarda küçük acil durumlardaki işlemleri en iyi duruma getirdiğini okuduğumu düşünüyorum ama karşılaştırma için emin değilim ya da emin değilim
phuclv

@ LưuVĩnhPhúc: Döngüden önce bir register yüklenebilir. Bu noktada, gerçek karşılaştırma her iki durumda da aynı sayıda talimat olacaktır.
cHao

Döngü op tarafından sadece bir örnekti ve soru örneğin bir z-endeksiydi, her biri kendi z-endeksine sahip 1000 nesneniz varsa ve bunları 100000000 ... 1000000999 ya da 10000 ... 10999 ve görüntülemeden önce sıralamak için bunların üzerinden geçiriyorsunuz, birçok karşılaştırma ve birçok yükleme talimatı var. Orada bir fark yaratabilir!
Falco

@Falko: Bu durumda, anında olur bile faktör olmaz; Bir sicile yüklemek ve karşılaştırmak neredeyse kaçınılmaz görünüyor.
cHao

@cHao: Eğer biri Z endekslerini birbirleriyle karşılaştırıyorsa, kayıtlara girmiş olurlar. Eğer biri farklı endeks aralıklarını farklı şekilde kullanıyorsa, bu hemen karşılaştırmaya yol açabilir. Normalde bir döngü başlamadan önce sabitler yüklenir, ancak örneğin biri bellekten bir çift değer okumak ve her bir çiftin ilk değerini 100000 aralığında beş farklı (tek biçimli olmayan aralıklarla) sabitlerle karşılaştırmak için gereken bir döngüye sahipse 100499'a kadar ve diğer beş sabit değere sahip diğer değer, 100250'yi (bir kayıt defterinde tutulur) çıkarmak ve daha sonra -250 ila 250 ... arasındaki değerlerle karşılaştırmak çok daha hızlı olabilir
supercat 4'15

5

Bu sorunun kısa cevabı, hayır , aynı veri tipinde saklandıklarını varsayarak bu sayıların büyüklüğüne dayanarak iki sayıyı karşılaştırmak için zaman farkı yoktur (örn. Hem 32-bit inç veya her ikisi de 64-bit).

Dahası, ALU kelime büyüklüğüne kadar, iki tamsayının birbiriyle karşılaştırılmasının, bir çıkarma işlemine eşdeğer önemsiz bir işlem olduğu için 1 saatten daha fazla sürmesi inanılmaz bir ihtimal. Sanırım şimdiye kadar ele aldığım her mimarın tek çevrim tam sayı karşılaştırması vardı.

İki sayının karşılaştırılmasının tek döngülü bir işlem olmadığı durumlarda karşılaştığımı düşünebildiğim tek vaka:

  • İşlenenleri almada gerçekte bir bellek gecikmesi olduğu, ancak karşılaştırmanın nasıl çalıştığı ile ilgisi olmayan talimatlar (ve genellikle RISC mimarilerinde, ancak x86 / x64 gibi CISC tasarımlarında mümkün olsa da) ile ilgisi yoktur.
  • Kayan nokta karşılaştırmaları, mimariye bağlı olarak çok döngülü olabilir.
  • Söz konusu sayılar ALU’nun kelime boyutuna uymuyor ve bu nedenle karşılaştırma birden fazla talimatlara bölünmüş olmalı.

4

@ RobertHarvey'in cevabı iyidir; Bu cevabı onun için bir ek olarak düşünün.


Ayrıca Şube Tahminini de göz önünde bulundurmalısınız :

Bilgisayar mimarisinde, dal tahmincisi, kesin olarak bilinmeden önce bir dalın (örneğin, eğer öyleyse bir yapı) hangi yöne gideceğini tahmin etmeye çalışan bir dijital devredir. Branş tahmininin amacı, talimat boru hattındaki akışı iyileştirmektir. Şube tahmin edicileri, x86 gibi birçok modern boru hattı işlemcisi mimarisinde yüksek performans elde etmede kritik bir rol oynamaktadır.

Temel olarak, örneğinizde, ifdöngü içindeki ifade her zaman aynı cevabı verirse, sistem hangi şekilde dallanacağını doğru tahmin ederek en iyi duruma getirebilir. Örneğinizde if, ilk davadaki ifade her zaman aynı sonucu verdiğinden, ikinci davadan biraz daha hızlı çalışacaktır.

Konuyla ilgili Mükemmel Yığın Taşması sorusu


Dal tahmini, dallanma zamanını etkiler ancak karşılaştırma zamanının kendisini etkilemez.
reirab

3

Bu uygulamaya bağlıdır, ancak çok, çok düşük bir ihtimaldir .

Çeşitli tarayıcı motorlarının uygulama ayrıntılarını okumadığımı itiraf ediyorum ve CSS, numaralar için belirli bir depolama türü belirtmediğini belirtti. Ancak, tüm büyük tarayıcıların CSS'deki sayısal ihtiyaçlarının çoğunu yerine getirmek için 64 bit çift duyarlıklı kayan nokta sayıları ("çiftler", C / C ++ 'dan bir terim ödünç almak için) kullandığını varsaymanın güvenli olduğuna inanıyorum. , çünkü bu numaralar için JavaScript'in kullandığı şeydir ve bu nedenle aynı türün kullanılması entegrasyonu kolaylaştırır.

Bilgisayarın bakış açısından, tüm iki katlar aynı miktarda veri taşır: değerin 1 veya -3.14 veya 1000000 veya 1e100 olup olmadığı 64 bit . Bu sayılar üzerinde işlem yapmak için geçen süre, bu sayıların gerçek değerine bağlı değildir, çünkü daima aynı miktarda veri üzerinde çalışır. İşlerin bu şekilde yapılması konusunda bir sapma vardır, çünkü çiftler tüm sayıları (veya aralarındaki tüm sayıları bile) doğru şekilde temsil edemezler, ancak çoğu mesele için yeterince yaklaşabilirler ve CSS'nin sayıları sayısal olarak değil Bundan daha fazla hassasiyete ihtiyaç duyacak kadar iddialıyım. Bunu, JavaScript ile doğrudan uyumlu olmanın avantajlarıyla birleştirin ve çiftler için oldukça güçlü bir durum elde edin.

Birinin numaralar için değişken uzunluklu bir kodlama kullanarak CSS yapması imkansız değildir. Birisi değişken uzunlukta kodlama kullandıysanız, o zaman çok sayıda crunch fazla veri var çünkü az sayıda karşı karşılaştırarak, büyük sayılar karşısında karşılaştırmaktan daha az pahalı olacaktır . Bu tür kodlamalar ikili dosyalardan daha kesin olabilir, ancak aynı zamanda çok daha yavaştır ve özellikle CSS için hassas kazançlar muhtemelen performansın düşmesi için yeterli değildir. Herhangi bir tarayıcının bu şekilde bir şey yaptığını öğrenmek çok şaşırırdım.

Şimdi, teoride, yukarıda söylediğim her şeyin olası bir istisnası var: sıfıra karşı karşılaştırma yapmak, genellikle diğer sayılara karşı karşılaştırma yapmaktan daha hızlıdır . Bunun sebebi sıfırın kısa olması değil (sebep buysa, o zaman 1 kadar hızlı olmalı, ama değil). Çünkü sıfır aldatmana izin veriyor. Tüm bitlerin kapalı olduğu tek sayıdır, yani değerlerden birinin sıfır olduğunu biliyorsanız, diğer değere bir sayı olarak bakmak zorunda kalmazsınız: eğer bitlerin herhangi biri eşit değilse sıfır, ve sıfırdan büyük mü yoksa küçük mü olduğunu görmek için yalnızca bir bit'e bakmak gerekir.


0

Bu kod her çalıştırıldığında yorumlanıyorsa, belirtmek ve yorumlamakla 10000000000000karşılaştırıldığında daha uzun sürdüğü için bir fark olacaktır 1000. Ancak, bu durumda tercümanların ilk açık optimizasyonudur: bir kez belirtmek ve belirteçleri yorumlamak.

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.