erken-tartışma-tüm-kötülük dersinin kökenidir-
Bununla birlikte, gereksiz verimden kaçınmak için edindiğim bazı alışkanlıklar var ve bazı durumlarda kodumu daha basit ve daha doğru hale getirdim.
Bu, genel prensiplerin bir tartışması değil, gereksiz verimsizlikleri koda eklemekten kaçınmanın farkında olması gereken bazı hususların tartışılmasıdır.
Büyük O'nu bilin
Bu muhtemelen yukarıdaki uzun tartışmalarla birleştirilmelidir. İç döngünün hesaplamayı tekrarladığı bir döngünün içindeki bir döngünün daha yavaş olacağı çok yaygın bir anlam ifade eder. Örneğin:
for (i = 0; i < strlen(str); i++) {
...
}
Eğer dize gerçekten uzunsa bu, korkunç bir zaman alacaktır, çünkü uzunluk döngünün her yinelemesinde yeniden hesaplanır. GCC'nin aslında bu durumu en iyi duruma getirdiğine dikkat edin, çünkü strlen()
saf bir işlev olarak işaretlenmiş.
Bir milyon 32-bit tamsayı sıralama , kabarcık sıralama gitmek yanlış yol olacaktır . Genel olarak, sıralama O (n * log n) zamanında yapılabilir (veya daha iyisi, radix sıralama durumunda), bu nedenle verilerinizin küçük olacağını bilmiyorsanız, en azından O (n) olan bir algoritma arayın. * log n).
Aynı şekilde, veritabanlarıyla uğraşırken, endekslerin farkında olun. Siz SELECT * FROM people WHERE age = 20
ve insanlar (yaş) hakkında bir endeksiniz yoksa, daha hızlı bir O (log n) indeks taramasından ziyade O (n) sıralı bir taramayı gerektirir.
Tamsayılı aritmetik hiyerarşisi
C de programlama yaparken, bazı aritmetik işlemlerin diğerlerinden daha pahalı olduğunu unutmayın. Tamsayılar için, hiyerarşi bu gibi bir şey gider (önce en ucuzu):
Verildiği takdirde, derleyici genellikle bir ana bilgisayarı hedefliyorsanız otomatik olarak n / 2
yapmak gibi şeyleri optimize eder n >> 1
, ancak gömülü bir cihazı hedefliyorsanız bu lüksü elde edemeyebilirsiniz.
Ayrıca, % 2
ve & 1
farklı anlambilim var. Bölünme ve modül, genellikle sıfıra doğru yuvarlanır, ancak uygulama tanımlanır. İyi ol ' >>
ve &
her zaman negatif sonsuzluğa yuvarlanır ki bence çok daha mantıklı geliyor. Örneğin, bilgisayarımda:
printf("%d\n", -1 % 2); // -1 (maybe)
printf("%d\n", -1 & 1); // 1
Dolayısıyla, mantıklı olanı kullanın. % 2
Aslen yazmaya giderken kullanarak iyi bir çocuk olduğunu düşünmeyin & 1
.
Pahalı kayan nokta işlemleri
Özellikle tam sayılarla uğraşırken, onlara gerçekten de gerekmeyen kod gibi pow()
ve zorlu kayan nokta işlemlerinden kaçının log()
. Örneğin, bir sayı okurken şunları yapın:
int parseInt(const char *str)
{
const char *p;
int digits;
int number;
int position;
// Count the number of digits
for (p = str; isdigit(*p); p++)
{}
digits = p - str;
// Sum the digits, multiplying them by their respective power of 10.
number = 0;
position = digits - 1;
for (p = str; isdigit(*p); p++, position--)
number += (*p - '0') * pow(10, position);
return number;
}
Sadece bu kullanımı pow()
(ve onu kullanması gereken int
<-> double
dönüşümleri) oldukça pahalı olmakla kalmaz, aynı zamanda hassasiyet kaybı için bir fırsat yaratır (bu arada, yukarıdaki kodun hassas sorunları yoktur). Bu yüzden matematiksel olmayan bir bağlamda kullanılan bu tür bir işlev gördüğümde inanıyorum.
Ayrıca, her yinelemede 10 ile çarpılan aşağıdaki "akıllı" algoritmanın aslında yukarıdaki koddan daha özlü olduğuna dikkat edin:
int parseInt(const char *str)
{
const char *p;
int number;
number = 0;
for (p = str; isdigit(*p); p++) {
number *= 10;
number += *p - '0';
}
return number;
}