Saya memiliki kode berikut:
if (this->_car.getAbsoluteAngle() <= 30 || this->_car.getAbsoluteAngle() >= 330)
this->_car.edir = Car::EDirection::RIGHT;
else if (this->_car.getAbsoluteAngle() > 30 && this->_car.getAbsoluteAngle() <= 60)
this->_car.edir = Car::EDirection::UP_RIGHT;
else if (this->_car.getAbsoluteAngle() > 60 && this->_car.getAbsoluteAngle() <= 120)
this->_car.edir = Car::EDirection::UP;
else if (this->_car.getAbsoluteAngle() > 120 && this->_car.getAbsoluteAngle() <= 150)
this->_car.edir = Car::EDirection::UP_LEFT;
else if (this->_car.getAbsoluteAngle() > 150 && this->_car.getAbsoluteAngle() <= 210)
this->_car.edir = Car::EDirection::LEFT;
else if (this->_car.getAbsoluteAngle() > 210 && this->_car.getAbsoluteAngle() <= 240)
this->_car.edir = Car::EDirection::DOWN_LEFT;
else if (this->_car.getAbsoluteAngle() > 240 && this->_car.getAbsoluteAngle() <= 300)
this->_car.edir = Car::EDirection::DOWN;
else if (this->_car.getAbsoluteAngle() > 300 && this->_car.getAbsoluteAngle() <= 330)
this->_car.edir = Car::EDirection::DOWN_RIGHT;
Saya ingin menghindari if
rantai s; itu sangat jelek. Adakah cara lain, mungkin lebih bersih, untuk menulis ini?
c++
if-statement
Oraekia
sumber
sumber
this->_car.getAbsoluteAngle()
sekali sebelum seluruh kaskade.this
(this->
) tidak diperlukan dan tidak benar-benar melakukan sesuatu yang baik untuk keterbacaan ..>
tes itu; mereka tidak diperlukan, karena masing-masing telah diuji (dalam arah yang berlawanan) dalamif
pernyataan sebelumnya .else if
.Jawaban:
Beginilah cara saya melakukannya. (Sesuai komentar saya sebelumnya).
sumber
q = a/b
danr = a%b
kemudianq * b + r
harus samaa
. Jadi sah di C99 untuk sisanya menjadi negatif. BorgLeader, Anda dapat memperbaiki masalah ini dengan(((angle % 360) + 360) % 360) / 30
.GetDirectionForAngle
adalah apa yang saya usulkan sebagai pengganti kaskade if / else, keduanya adalah O (1) ...Anda dapat menggunakan
map::lower_bound
dan menyimpan batas atas setiap sudut di peta.Contoh kerja di bawah ini:
sumber
table[angle%360/30]
jawaban karena murah dan tanpa cabang. Jauh lebih murah daripada loop pencarian pohon, jika ini mengkompilasi ke asm yang mirip dengan sumbernya. (std::unordered_map
biasanya tabel hash, tetapistd::map
biasanya pohon biner merah-hitam. Jawaban yang diterima secara efektif digunakanangle%360 / 30
sebagai fungsi hash yang sempurna untuk sudut (setelah mereplikasi beberapa entri, dan jawaban Bijay bahkan menghindarinya dengan offset)).lower_bound
array yang diurutkan. Itu akan jauh lebih efisien daripada amap
.this->_car.getAbsoluteAngle()
dengan var tmp, dan menghapus perbandingan yang berlebihan dari masing-masingif()
klausa OP (memeriksa sesuatu yang sudah cocok if ()) sebelumnya. Atau gunakan saran sort-array @ wilx.Buat sebuah array, yang setiap elemennya dikaitkan dengan blok 30 derajat:
Kemudian Anda dapat mengindeks array dengan sudut / 30:
Tidak perlu perbandingan atau percabangan.
Namun hasilnya sedikit melenceng dari aslinya. Nilai di perbatasan, yaitu 30, 60, 120, dll. Ditempatkan di kategori berikutnya. Misalnya, dalam kode asli nilai yang valid
UP_RIGHT
adalah 31 hingga 60. Kode di atas menetapkan 30 hingga 59 keUP_RIGHT
.Kita bisa menyiasatinya dengan mengurangi 1 dari sudut:
Ini sekarang memberi kita
RIGHT
30,UP_RIGHT
60, dll.Dalam kasus 0, ekspresi menjadi
(-1 % 360) / 30
. Ini valid karena-1 % 360 == -1
dan-1 / 30 == 0
, jadi kami masih mendapatkan indeks 0.Bagian 5.6 dari standar C ++ mengonfirmasi perilaku ini:
EDIT:
Ada banyak pertanyaan yang diajukan tentang keterbacaan dan pemeliharaan konstruksi seperti ini. Jawaban yang diberikan oleh motoDrizzt adalah contoh yang baik untuk menyederhanakan konstruksi asli yang lebih mudah dipelihara dan tidak terlalu "jelek".
Memperluas jawabannya, berikut adalah contoh lain yang menggunakan operator terner. Karena setiap kasus di posting asli ditetapkan ke variabel yang sama, menggunakan operator ini dapat membantu meningkatkan keterbacaan lebih lanjut.
sumber
Kode itu tidak jelek, sederhana, praktis, mudah dibaca dan mudah dimengerti. Itu akan diisolasi dengan metodenya sendiri, jadi tidak ada yang harus menghadapinya dalam kehidupan sehari-hari. Dan untuk berjaga-jaga jika seseorang harus memeriksanya -mungkin karena dia sedang men-debug aplikasi Anda untuk masalah di tempat lain- sangat mudah sehingga dia membutuhkan waktu dua detik untuk memahami kode dan fungsinya.
Jika saya melakukan debug seperti itu, saya akan senang tidak menghabiskan lima menit mencoba memahami apa fungsi fungsi Anda. Dalam hal ini, semua fungsi lain gagal sepenuhnya, karena mereka mengubah rutinitas bebas bug yang sederhana, lupakan saja, dalam kekacauan yang rumit sehingga orang-orang saat men-debug akan dipaksa untuk menganalisis dan menguji secara mendalam. Sebagai manajer proyek, saya sendiri sangat kecewa dengan pengembang yang mengambil tugas sederhana dan alih-alih menerapkannya dengan cara yang sederhana dan tidak berbahaya, malah membuang waktu untuk menerapkannya dengan cara yang terlalu rumit. Pikirkan saja semua waktu yang Anda sia-siakan untuk memikirkannya, lalu datang ke SO bertanya, dan semuanya hanya demi pemeliharaan dan keterbacaan yang semakin buruk.
Meskipun demikian, ada kesalahan umum dalam kode Anda yang membuatnya kurang dapat dibaca, dan beberapa peningkatan dapat Anda lakukan dengan mudah:
Letakkan ini ke dalam metode, tetapkan nilai yang dikembalikan ke objek, ciutkan metode, dan lupakan selama sisa waktu.
PS ada bug lain di atas ambang 330, tetapi saya tidak tahu bagaimana Anda ingin mengobatinya, jadi saya tidak memperbaikinya sama sekali.
Pembaruan nanti
Sesuai komentar, Anda bahkan dapat menyingkirkan yang lain jika:
Saya tidak melakukannya karena saya merasa bahwa poin tertentu itu hanya menjadi masalah preferensi sendiri, dan cakupan jawaban saya adalah (dan sedang) memberikan perspektif yang berbeda untuk kekhawatiran Anda tentang "keburukan kode". Bagaimanapun, seperti yang saya katakan, seseorang menunjukkannya di komentar dan saya pikir masuk akal untuk menunjukkannya.
sumber
else if
,if
sudah cukup.else if
. Saya merasa berguna untuk dapat melihat sekilas blok kode, dan melihat bahwa itu adalah pohon keputusan, daripada sekelompok pernyataan yang tidak terkait. Ya,else
ataubreak
tidak diperlukan untuk compiler setelah areturn
, tetapi berguna bagi orang yang melihat sekilas kode.elseif
/elsif
kata kunci yang terpisah , atau Anda secara teknis menggunakan blok satu pernyataan yang kebetulan dimulaiif
, seperti di sini. Contoh cepat dari apa yang menurut saya sedang Anda pikirkan, dan apa yang saya pikirkan: gist.github.com/IMSoP/90bc1e9e2c56d8314413d7347e76532aelse
membuat Anda melakukan itu, itu adalah panduan gaya yang buruk yang tidak dikenalielse if
sebagai pernyataan yang berbeda. Saya akan selalu menggunakan kawat gigi, tetapi saya tidak akan pernah menulis kode seperti itu, seperti yang saya tunjukkan dalam inti saya.Dalam pseudocode:
Jadi, kita memiliki
0-60
,60-90
,90-150
, ... sebagai kategori. Di setiap kuadran 90 derajat, satu bagian memiliki 60, satu bagian memiliki 30. Jadi, sekarang:Gunakan indeks dalam larik yang berisi enum dalam urutan yang sesuai.
sumber
sumber
Mengabaikan kasus pertama Anda
if
yang merupakan kasus khusus, sisanya mengikuti pola yang sama persis: min, maks, dan arah; pseudo-code:Membuat C ++ nyata ini mungkin terlihat seperti:
Sekarang, daripada menulis banyak
if
, cukup ulangi berbagai kemungkinan Anda:(
throw
ing pengecualian daripadareturn
ingNONE
adalah pilihan lain).Yang kemudian akan Anda panggil:
Teknik ini dikenal sebagai pemrograman berbasis data . Selain menghilangkan sekelompok
if
s, ini akan memungkinkan Anda untuk dengan mudah menambahkan lebih banyak arah (misalnya, NNW) atau mengurangi nomor (kiri, kanan, atas, bawah) tanpa mengulang kode lain.(Menangani kasus khusus pertama Anda dibiarkan sebagai "latihan untuk pembaca." :-))
sumber
if(angle <= angleRange.max)
tetapi +1 untuk menggunakan fitur C ++ 11 sepertienum class
.Meskipun varian yang diusulkan berdasarkan tabel pencarian
angle / 30
mungkin lebih disukai, berikut adalah alternatif yang menggunakan pencarian biner berkode keras untuk meminimalkan jumlah perbandingan.sumber
Jika Anda benar-benar ingin menghindari duplikasi, Anda dapat mengekspresikannya sebagai rumus matematika.
Pertama-tama, asumsikan bahwa kita menggunakan Enum @ Geek
Sekarang kita dapat menghitung enum menggunakan matematika integer (tanpa membutuhkan array).
Seperti yang ditunjukkan @motoDrizzt, kode yang ringkas belum tentu merupakan kode yang dapat dibaca. Itu memang memiliki keuntungan kecil yang mengekspresikannya sebagai matematika membuatnya eksplisit bahwa beberapa arah mencakup busur yang lebih luas. Jika Anda ingin pergi ke arah ini, Anda dapat menambahkan beberapa pernyataan untuk membantu memahami kode.
Setelah menambahkan asserts Anda telah menambahkan duplikasi, tetapi duplikasi dalam asserts tidak terlalu buruk. Jika Anda memiliki pernyataan yang tidak konsisten, Anda akan segera mengetahuinya. Pernyataan dapat dikompilasi dari versi rilis agar tidak membengkak dieksekusi yang Anda distribusikan. Namun demikian, pendekatan ini mungkin paling dapat diterapkan jika Anda ingin mengoptimalkan kode daripada membuatnya tidak terlalu jelek.
sumber
Saya Terlambat ke pesta, tapi Kita bisa menggunakan bendera enum dan pemeriksaan jangkauan untuk melakukan sesuatu yang rapi.
pemeriksaan (pseudo-code), dengan asumsi sudut absolut (antara 0 dan 360):
sumber