masukkan kuliah prematur-diskusi-adalah-akar-dari-semua-kejahatan
Yang mengatakan, berikut adalah beberapa kebiasaan saya sudah masuk untuk menghindari efisiensi yang tidak perlu, dan dalam beberapa kasus, membuat kode saya lebih sederhana dan lebih benar juga.
Ini bukan diskusi tentang prinsip-prinsip umum, tetapi beberapa hal yang harus diperhatikan untuk menghindari memasukkan inefisiensi yang tidak perlu ke dalam kode.
Ini mungkin harus digabungkan ke dalam diskusi panjang di atas. Cukup masuk akal bahwa loop di dalam loop, di mana loop dalam mengulangi perhitungan, akan menjadi lebih lambat. Sebagai contoh:
for (i = 0; i < strlen(str); i++) {
...
}
Ini akan membutuhkan banyak waktu jika string benar-benar panjang, karena panjangnya dihitung ulang pada setiap iterasi dari loop. Perhatikan bahwa GCC sebenarnya mengoptimalkan kasus ini karena strlen()
ditandai sebagai fungsi murni.
Saat menyortir sejuta bilangan bulat 32-bit, bubble sort akan menjadi cara yang salah . Secara umum, penyortiran dapat dilakukan dalam waktu O (n * log n) (atau lebih baik, dalam hal penyortiran radix), jadi kecuali Anda tahu data Anda akan menjadi kecil, cari algoritma yang setidaknya O (n * log n).
Demikian juga, ketika berhadapan dengan basis data, waspadai indeks. Jika Anda SELECT * FROM people WHERE age = 20
, dan Anda tidak memiliki indeks pada orang (usia), itu akan memerlukan pemindaian berurutan O (n) daripada pemindaian indeks O (log n) yang jauh lebih cepat.
Hirarki aritmatika integer
Ketika pemrograman dalam C, ingatlah bahwa beberapa operasi aritmatika lebih mahal daripada yang lain. Untuk bilangan bulat, hierarki berbunyi seperti ini (paling murah dulu):
Memang, compiler akan hal-hal yang biasanya mengoptimalkan seperti n / 2
untuk n >> 1
secara otomatis jika Anda menargetkan komputer mainstream, tetapi jika Anda menargetkan perangkat tertanam, Anda mungkin tidak mendapatkan kemewahan itu.
Juga, % 2
dan & 1
memiliki semantik yang berbeda. Pembagian dan modulus biasanya membulat ke nol, tetapi implementasinya didefinisikan. Baik >>
dan &
selalu berputar ke arah infinity negatif, yang (menurut saya) jauh lebih masuk akal. Misalnya, di komputer saya:
printf("%d\n", -1 % 2); // -1 (maybe)
printf("%d\n", -1 & 1); // 1
Karena itu, gunakan apa yang masuk akal. Jangan berpikir Anda menjadi anak yang baik dengan menggunakan % 2
ketika Anda awalnya akan menulis & 1
.
Operasi floating point yang mahal
Hindari operasi floating point berat seperti pow()
dan log()
dalam kode yang tidak benar-benar membutuhkannya, terutama ketika berhadapan dengan bilangan bulat. Ambil, misalnya, membaca nomor:
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;
}
Tidak hanya penggunaan ini pow()
(dan konversi int
<-> yang double
diperlukan untuk menggunakannya) agak mahal, tetapi juga menciptakan peluang untuk kehilangan presisi (kebetulan, kode di atas tidak memiliki masalah presisi). Itu sebabnya saya meringis ketika saya melihat fungsi jenis ini digunakan dalam konteks non-matematika.
Perhatikan juga bagaimana algoritma "pintar" di bawah ini, yang dikalikan 10 pada setiap iterasi, sebenarnya lebih ringkas daripada kode di atas:
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;
}