Dalam dunia akademis kasus terburuk, Big O diajarkan di atas segalanya. Dibandingkan dengan kompleksitas ruang, analisis kasus normal, kesederhanaan atas kompleksitas, dll.
Khususnya untuk pemrograman game dan industri, apa yang paling penting dan mengapa?
Referensi akan sangat membantu.
software-engineering
algorithm
David Young
sumber
sumber
Jawaban:
Seperti halnya setiap pertanyaan lain tentang "apa Satu Jalur Sejati", ini semua adalah alat di kotak alat Anda dan ada kasus di mana O besar mengalahkan segalanya, dan tempat-tempat di mana itu tidak masalah (tm).
Anda akan "tidak pernah" menulis pemecah fisika tanpa khawatir tentang big-O. Anda tidak akan menerapkan algoritme pengurutan (untuk apa pun kecuali kumpulan data terkecil) tanpa khawatir. Jika Anda menulis game berjaringan, Anda akan khawatir dengan kinerja dan skala lalu lintas jaringan per pengguna.
Anda mungkin tidak begitu khawatir tentang big-O ketika, yah, saya benar-benar tidak bisa memikirkan waktu tetapi saya yakin ada beberapa. :) Syukurlah, sebagian besar hal yang kita lakukan dalam game berskala linear; Anda ingin membaca file dari disk? Ini akan memakan waktu yang sebanding secara linier dengan ukuran file (mengabaikan faktor pencarian konstan dan kemungkinan konsekuensi ukuran sektor).
Namun, bagaimana jika Anda ingin menemukan entitas tertentu dalam daftar entitas? Itu pencarian linear setiap kali Anda melakukannya. Jika Anda perlu menemukan pemain satu kali untuk setiap entitas di dunia, pendekatan ini akan membunuh Anda untuk semua hal kecuali permainan yang paling sepele, dan bahkan mungkin perlu "mengoptimalkan" pencarian ini sebagai waktu yang konstan (mis. Simpan dari indeks atau pointer ke pemain di suatu tempat), memberi Anda lebih banyak waktu untuk melakukan hal-hal lain yang sebenarnya terlihat oleh pemain.
Saya kira itu merangkumnya, meskipun; setiap kali prosesor melakukan sesuatu yang tidak secara langsung dapat diwakili oleh pemain, itu membuang-buang waktu. Memaksimalkan jumlah waktu prosesor menghitung data yang akan ditampilkan kepada pemain adalah memaksimalkan WOW! Anda memberi pemain.
sumber
Aturan praktis saya adalah bahwa kecuali Anda O (menakutkan), masalah Anda yang lain lebih relevan.
Aturan saya yang lain adalah bahwa data adalah raja. Kecuali jika Anda membuat profil kode Anda dengan set data realistis, Anda hanya menebak-nebak.
Sunting: Untuk sedikit lebih detail, O besar Anda tidak begitu penting karena (setidaknya dalam pengalaman saya) sebagian besar set data Anda relatif kecil. Anda mungkin tidak peduli dengan batas kinerja Anda saat bekerja dengan struktur data dengan elemen kurang dari beberapa ratus. Dan jika daftar Anda memiliki elemen 100k + maka Anda benar-benar perlu mempertimbangkan semua aspek algoritma Anda. Itu, dan dari pengalaman saya, memori lebih merupakan faktor pembatas daripada kecepatan CPU. Algoritme memonopoli memori yang lebih cepat mungkin tidak sebagus yang lebih ramping tetapi lebih lambat tergantung pada kasus penggunaan Anda.
sumber
Big O penting sebagian besar waktu, tetapi kadang-kadang algoritma yang tampaknya "lebih buruk" dalam teori ternyata jauh lebih cepat dalam praktik.
Lihatlah contoh bagus dari Tony Albrecht: http://seven-degrees-of-freedom.blogspot.com/2010/07/question-of-sorts.html
Anda menemukan ini di mana-mana dalam pengembangan game di mana jumlah item dalam operasi itu begitu besar sehingga algoritma yang sangat berbeda lebih cepat, atau sangat kecil sehingga algoritma dumber cukup (atau cocok dalam cache sehingga baik menimpa efisiensi dari algoritma yang lebih baik ).
Masalah dengan Big O adalah bahwa itu adalah penunjukan generik dari kompleksitas tugas dan tidak memperhitungkan kompleksitas perangkat keras target modern, juga tidak menawarkan wawasan tentang overhead waktu pengaturan.
Dalam banyak kasus, solusi optimal terbaik adalah dua langkah. Dalam praktiknya, pengembang game cenderung cenderung ke algoritma O rendah tetapi seimbang terhadap biaya dalam pengembangan waktu, atau debugging. Setelah Anda memiliki solusi yang masuk akal, Anda selalu harus melihat bagaimana perangkat keras menangani tugas, dan bagaimana membiarkan perangkat keras menyelesaikan lebih banyak dalam waktu yang lebih singkat.
sumber
Ketika aku coding di-mesin, saya sering hanya peduli dengan tetap
n
: Aku sudah punya partisi spacial membatasi jumlah objek yang menerimaupdate()
,physics()
danrender()
sekitar orang-orang di layar dan sekitarnya. Ukuran batch maksimum biasanya didefinisikan dengan cukup baik per-game, meskipun itu selalu sedikit lebih besar dari yang Anda rencanakan.Dalam hal ini saya tidak terlalu peduli dengan big-O karena saya prihatin dengan faktor pengganda dan orde rendah yang konstan. Untuk fungsi dengan runtime seperti
a*n^2 + b*n + c
(yangO(n^2)
), saya sering lebih peduli dengan mengurangia
dan mungkin menghilangkanc
. Biaya setup atau teardownc
bisa menjadi besar secara proporsional vs keciln
.Namun, ini bukan untuk mengatakan bahwa big-O (atau lebih khusus big-theta ) adalah indikator bau kode yang hebat. Lihat suatu
O(n^4)
tempat, atau lebih buruk lagiO(k^n)
waktu geometris, dan inilah saatnya untuk memastikan Anda mempertimbangkan opsi lain.Saya umumnya jauh lebih peduli tentang optimalitas big-O dan melompat-lompat untuk menemukan algoritma dengan big-O rendah ketika saya berurusan dengan alat data make. Sementara jumlah objek dalam level tertentu / area streaming umumnya didefinisikan dengan baik, jumlah total objek / aset seni / file konfigurasi / dll di seluruh permainan mungkin tidak. Ini juga jumlah yang jauh lebih besar. Meskipun menjalankan pembuatan data paralel, kami masih menunggu dalam urutan satu menit (saya tahu, merengek - pembuatan data untuk konsol dapat memakan waktu berjam-jam - kami sebagian besar adalah game genggam kecil) untuk menjalani
jam data-clean && jam data
siklus.Untuk memberikan contoh spesifik: ini benar-benar tidak terkendali dengan algoritme streaming ubin latar belakang yang mengalirkan ubin 8x8 256-warna. Sangat berguna untuk membagikan buffer streaming di antara "lapisan" latar belakang, dan kami mungkin memiliki hingga 6 dari mereka di level tertentu yang berbagi buffer yang sama. Masalahnya adalah bahwa memperkirakan ukuran buffer yang dibutuhkan didasarkan pada posisi yang memungkinkan dari semua 6 lapisan - dan jika mereka adalah bilangan prima lebar / tinggi / kecepatan gulir, Anda dengan cepat mulai melakukan pencarian lengkap - yang mulai mendekat
O(6^numTiles)
- yang berada dalam kategori "lebih lama dari jagad raya sekitar" dalam banyak kasus. Untungnya kebanyakan case hanya 2-3 layer, tetapi meskipun demikian, kami berada di atas runtime setengah jam. Saat ini, kami mengambil sampel subset yang sangat kecil dari kemungkinan ini, meningkatkan granularity hingga sejumlah waktu yang telah berlalu (atau kami telah menyelesaikan tugas, yang mungkin terjadi untuk konfigurasi double-layer kecil). Kami menaikkan perkiraan ini sedikit berdasarkan statistik sebelumnya tentang seberapa sering kami terbukti salah, dan kemudian menambahkan sedikit bantalan tambahan untuk ukuran yang baik.Satu contoh lain yang menyenangkan: pada game PC beberapa waktu lalu, insinyur utama bereksperimen untuk sementara waktu dengan melewatkan daftar . Memori overhead pada akhirnya menyebabkan lebih banyak efek cache, yang menambahkan semacam pengganda non-konstan ke seluruh urusan - jadi mereka benar-benar bukan pilihan yang baik sama sekali untuk kecil
n
. Tetapi untuk daftar yang lebih besar diurutkan di mana pencarian sering dilakukan, mereka memberikan manfaat.(Saya sering menemukan bahwa algoritma naif lebih tinggi big-O, lebih cepat pada set data yang lebih kecil, dan lebih mudah untuk dipahami; yang lebih menarik / kompleks (misalnya patricia trie) lebih sulit bagi orang untuk memahami dan memelihara, tetapi kinerja yang lebih tinggi pada yang lebih besar set data.)
sumber
Ini bisa berguna, tetapi juga tidak relevan. Ambil, misalnya, gim terbaru saya, yang merupakan tiruan dari Smash TV. Game top-down, monster-monster berdatangan dari samping, kamu tembak mereka.
Sekarang ada banyak cara pintar untuk menentukan tabrakan. Anda dapat menggunakan KDtrees untuk mempartisi ruang sehingga Anda tidak menguji peluru terhadap monster yang tidak mungkin mereka pukul. Dan, tentu saja, saya bisa saja pintar, dan saya bisa melakukannya.
Tapi aku merasa malas jadi aku hanya membandingkan setiap peluru dengan setiap monster. Bahkan dalam situasi paling sibuk, kode tumbukan menggunakan jauh lebih sedikit dari 10% CPU game pada 60fps. Big-O: Tidak penting.
Demikian pula, saya memiliki permainan gaya-4x di mana Anda membangun kota di pulau-pulau, dan kadang-kadang kota-kota dihancurkan. Saya bisa saja pintar dan berusaha mengurangi pendapatan kota yang hancur dari variabel pendapatan. Tetapi saya tidak melakukannya. Saya baru saja menghapus pendapatan dan menghitung ulang dari awal setiap kali ada perubahan. Sama sekali tidak relevan dalam hal CPU.
Big-O sama pentingnya dalam permainan seperti halnya dalam hal lain: artinya, sama sekali tidak penting, sampai menjadi kritis.
Pergi tulis beberapa kode. Jika terlalu lambat, maka profil itu.
sumber
Analisis Big-O penting, tetapi itu bukan hal pertama yang dipikirkan dalam pengembangan game. Karena membuat game melibatkan banyak kode rumit, saya selalu merekomendasikan Kesederhanaan Kode sebagai kriteria pertama untuk suatu algoritma. Algoritma dengan pembukuan yang rumit hanya membuang waktu Anda.
Saya pikir sangat penting bahwa gim Anda selalu berjalan pada kecepatan 60 fps selama pengembangan. Ketika Anda mencelupkan di bawah itu, hal pertama yang Anda lakukan adalah menjalankan profiler. Setelah Anda menemukan bottleneck, Anda menyerangnya. Banyak waktu yang Anda butuhkan untuk melakukan hal-hal non-coding seperti memberitahu desainer tingkat untuk menempatkan lebih sedikit barang di suatu daerah (dan memberi mereka alat untuk itu).
Terkadang Anda benar-benar mengidentifikasi beberapa kode yang perlu dipercepat. Saya menemukan ini sebagai rekayasa yang menyenangkan! Saya berharap memiliki lebih banyak kesempatan untuk melakukan ini. Dan tentu saja Anda ingin beralih mengubah satu hal pada satu waktu dan mengukur kinerja. Masalah tipical yang saya temukan adalah:
sumber
Notasi O besar adalah dengan definisi kompleksitas asimptotik - yaitu, ia menunjukkan bagaimana skala waktu ketika N (atau variabel apa pun yang Anda miliki) menjadi "sangat" besar. Untuk mengulangi komentar Tetrad (yang saya angkat) "data adalah raja". Jika N "sangat besar" dalam situasi spesifik Anda, itu penting, jika N "sangat kecil" itu tidak masalah. Pengalaman dan praktik akan memberi Anda perasaan bagaimana mengukur "sangat besar" dan "sangat kecil".
Jelas, selalu profil terlebih dahulu, dan optimalkan yang terakhir (kecuali jika Anda melakukan studi kelayakan fitur).
sumber
Pentingnya Big-O dalam perangkat lunak Anda adalah O (N 2 ). Ketika N tumbuh, pentingnya memiliki algoritma yang tepat tumbuh lebih banyak lagi. :)
sumber
Big-O hanyalah panduan - sesuatu yang memberi tahu Anda kinerja kasar yang dapat Anda harapkan dari suatu algoritma - dan bagaimana Anda seharusnya mengharapkan kinerja untuk meningkat saat Anda meningkatkan ukuran dataset . Anda harus mengingat dua hal utama terkait Big-O:
1) Jika Anda memiliki dua algoritma yang sebagian besar melakukan hal yang sama tetapi satu memiliki O yang lebih baik, Anda mungkin harus menggunakan yang itu (jelas)
2) Big O berkaitan dengan analisis asimptotik . Big-O hanya benar-benar berperan ketika n besar . Sebagai contoh, suatu algoritma O (n) dapat sangat mirip dalam kinerjanya dengan suatu O (n ^ 2) satu .. untuk n kecil . Jika Anda berbicara tentang sebuah algoritma yang membutuhkan n ^ 2 operasi per titik, tapi n = 2 atau n = 3, maka ada tidak banyak perbedaan antara O (n ^ 2) algoritma (mengambil 4 dan 9 ops resp) dan sebuah O (n) satu (2 dan 3 ops resp.). Namun, jika n = 9, maka Anda tiba-tiba berbicara tentang 81 operasi untuk algoritma O (n ^ 2) dan hanya 9 untuk O (n) satu - perbedaan yang lebih besar - dan jika n = 100, maka Anda adalah berbicara tentang 100 ops vs 10000 - perbedaan yang jauh lebih besar.
Jadi Anda harus selalu mempertimbangkan Big-O dalam cahaya itu: ini dimaksudkan untuk membandingkan algoritma yang melakukan hal yang sama berdasarkan kinerja kasus terburuk saat n menjadi besar . Perbedaan antara algoritma mungkin sangat kecil bila n sangat kecil.
sumber
Saya tidak punya referensi tetapi Big O setidaknya berguna untuk diperhatikan ketika menganalisis masalah dan diskusi. Di sisi lain, tentu saja, jika versi O (log n) memiliki cara yang lebih melibatkan O daripada versi O (n) itu adalah perbandingan yang bisa diperdebatkan. Dan seperti segalanya, selalu ada trade off. Kompleksitas ruang bisa menjadi masalah, meskipun itu bisa diekspresikan dalam O secara umum juga. Analisis kasus normal ... kurang begitu, karena Anda tidak ingin outlier juga lonjakan. Kesederhanaan atas kerumitan, menurut saya, relatif tidak berguna dalam pengembangan game karena kecepatan hampir selalu menjadi masalah, jadi kecuali kesederhanaan mengarah ke percepatan (tapi kemudian itu berarti kasus kompleks Anda salah karena alasan yang salah) kesederhanaan harus pergi keluar dari jendela demi kecepatan. Tapi Big O pasti berguna,
sumber
Saat Anda membuat prototipe fungsi gim atau aspek gim, Anda tidak perlu khawatir untuk mengoptimalkannya sama sekali .
Dalam proses pembuatan prototipe dan belajar tentang keistimewaan fungsi itu, optimasi yang diperlukan akan menjadi jelas & akan menjadi faktor dalam desain akhir seperti sifat kedua ... sebagian besar waktu.
Jangan dipikirkan.
sumber
Seharusnya tidak menjadi yang terbaik dan yang terakhir. Tapi itu membantu memilah masalah yang jelas yang dapat menyebabkan kinerja hit; mengapa menggunakan sesuatu dalam waktu O (n ^ 2), ketika Anda dapat melakukan hal yang sama dalam waktu O (log n)?
Saya pikir itu berlaku untuk permainan lebih dari kebanyakan industri lain, karena pasar adalah orang yang paling memperhatikan masalah kecepatan. Seseorang yang menggunakan pengolah kata tidak akan peduli jika ada penundaan setengah detik untuk melakukan tindakan X, tetapi gamer mungkin akan pergi 'omg omg game Y sangat lambat sehingga butuh waktu lama untuk melakukan tindakan Z'.
sumber
Dalam pengembangan game (dan sebagian besar lainnya), kami mengeluh tentang satu operasi ekstra yang dilakukan per loop:
vs.
Sebagian besar gim modern memiliki fisika, dan Anda akan menemukan masalah simulasi n-body . Dalam algoritma naif, itu O (n ^ 2), tetapi ada optimasi yang membuatnya O (n log n) (tetapi mengorbankan beberapa akurasi).
Anda bisa mengatakan, Anda tidak memprogram gravitasi dan interaksi partikel, tetapi bagaimana dengan perilaku tim pasukan (zombie) di mana mereka bergerak bergantung pada lokasi lain (dengan kata yang lebih spesifik: berkerumun)?
Dalam algoritma pendeteksian tabrakan konvensional, kompleksitas waktu adalah O (n ^ 2), seperti n-body. Namun, ada cara yang lebih baik: Pisahkan dunia ke banyak bagian kecil sehingga hanya objek di dalam bagian yang sama yang terdeteksi tabrakan. Lihat http://www.videotutorialsrock.com/opengl_tutorial/collision_detection/text.php .
Jika gim Anda dapat skrip, JANGAN membuat skrip menulis algoritma O-n (2 ^) (dan lebih) 2-angka dalam skrip, seperti mencari tas pengguna. Sebaliknya, buat fungsi bawaan dalam kode.
sumber
Di dunia nyata hanya kinerja mentah yang diperhitungkan. Sekarang, Big-O dari suatu algoritma mungkin berfungsi sebagai indikasi pertama tentang apa yang harus digunakan, tetapi tergantung pada perangkat keras implementasinya mungkin sangat tidak efisien. Misalnya melakukan pencarian linear seringkali lebih cepat daripada pencarian biner karena Anda mendapatkan akses memori linier dan tidak ada cabang.
Selain itu, karena arah saat ini dalam platform dan arsitektur multi-ulir, Big-O kehilangan banyak arti karena hanya memperhitungkan skalabilitas vertikal memori atau data yang disentuh per operasi alih-alih juga mempertimbangkan bagaimana algoritma sisik dengan jumlah utas yang lebih besar.
sumber