Meskipun ada banyak cara untuk membalik urutan bit dalam satu byte, saya ingin tahu apa yang "paling sederhana" untuk diterapkan oleh pengembang. Dan dengan membalik maksud saya:
1110 -> 0111
0010 -> 0100
Ini mirip dengan, tetapi bukan duplikat dari pertanyaan PHP ini .
Ini mirip dengan, tetapi bukan duplikat dari pertanyaan C ini . Pertanyaan ini menanyakan metode termudah untuk diterapkan oleh pengembang. "Algoritma Terbaik" berkaitan dengan memori dan kinerja cpu.
c++
c
bit-manipulation
nathan
sumber
sumber
Jawaban:
Jika Anda berbicara tentang satu byte, pencarian tabel mungkin adalah pilihan terbaik, kecuali karena alasan tertentu Anda tidak memiliki 256 byte yang tersedia.
sumber
unsigned int rtable[] = {0x800, 0x4000, ...};
. Kemudian buang skrip dan lupakan Anda pernah memilikinya. Ini jauh lebih cepat untuk menulis daripada kode C ++ yang setara, dan itu hanya akan berjalan sekali, jadi Anda mendapatkan runtime O (1) dalam kode C ++ Anda.Ini harus bekerja:
Pertama empat bit kiri ditukar dengan empat bit kanan. Kemudian semua pasangan yang berdekatan ditukar dan kemudian semua bit tunggal yang berdekatan. Ini menghasilkan urutan terbalik.
sumber
Saya pikir tabel pencarian harus menjadi salah satu metode paling sederhana. Namun, Anda tidak memerlukan tabel pencarian lengkap.
Ini cukup sederhana untuk membuat kode dan memverifikasi secara visual.
Pada akhirnya ini bahkan mungkin lebih cepat daripada tabel penuh. Bit arith murah dan tabelnya mudah dipasang pada baris cache.
sumber
b0001(1) -> b1000(0x8)
,b0010(2) -> b0100(0x4)
,b1010(10) -> b0101(0x5)
. Lihat polanya? Ini cukup sederhana sehingga Anda dapat menghitungnya di kepala Anda (jika Anda dapat membaca biner, jika tidak Anda akan memerlukan kertas untuk menyelesaikannya). Adapun lompatan bahwa membalik bilangan bulat 8 bit sama dengan membalik bagian 4 bit kemudian menukarnya; Saya mengklaim pengalaman dan intuisi (atau sihir).Lihat peretasan yang sedikit memutar-mutar untuk banyak solusi. Copypasting dari sana jelas mudah diterapkan. =)
Misalnya (pada CPU 32-bit):
Jika dengan "mudah diimplementasikan" berarti sesuatu yang dapat dilakukan tanpa referensi dalam ujian atau wawancara kerja, maka taruhan teraman mungkin adalah menyalin bit yang tidak efisien satu per satu ke variabel lain dalam urutan terbalik (sudah ditunjukkan di jawaban lain) ).
sumber
Karena tidak ada yang memposting solusi pencarian tabel lengkap, inilah solusi saya:
sumber
EDIT:
Mengonversinya menjadi template dengan bitcount opsional
sumber
sizeof(T)*8
dengansizeof(T)*CHAR_BITS
.sizeof(T)*CHAR_BIT
denganstd::numeric_limits<T>::digits
(hampir 4 tahun kelayakan nanti).CHAR_BIT
tidakCHAR_BITS
.Dua baris:
atau jika Anda memiliki masalah dengan bagian "0b1":
"original" adalah byte yang ingin Anda balikkan. Hasilnya "dibalik", diinisialisasi ke 0.
sumber
Meskipun mungkin tidak portabel, saya akan menggunakan bahasa assembly.
Banyak bahasa assembly memiliki instruksi untuk memutar sedikit ke dalam bendera carry dan memutar bendera carry ke dalam kata (atau byte).
Algoritmanya adalah:
Kode bahasa tingkat tinggi untuk ini jauh lebih rumit, karena C dan C ++ tidak mendukung rotating to carry dan rotating from carry. Bendera pembawa harus dimodelkan.
Edit: Bahasa assembly misalnya
sumber
Saya menemukan solusi berikut lebih sederhana daripada algoritma mengutak-atik bit lain yang pernah saya lihat di sini.
Itu mendapatkan setiap bit dalam byte, dan menggesernya sesuai, mulai dari yang pertama hingga yang terakhir.
Penjelasan:
sumber
Cara termudah mungkin adalah dengan mengulang posisi bit dalam satu lingkaran:
sumber
CHAR_BIT
jika Anda menganggapchar
memiliki 8 bit?Anda mungkin tertarik pada
std::vector<bool>
(yang sangat padat) danstd::bitset
Ini harus yang paling sederhana seperti yang diminta.
Pilihan lain mungkin lebih cepat.
EDIT: Saya berhutang solusi menggunakan
std::vector<bool>
Contoh kedua membutuhkan ekstensi c ++ 0x (untuk menginisialisasi array dengan
{...}
). Keuntungan menggunakan abitset
atau astd::vector<bool>
(atau aboost::dynamic_bitset
) adalah Anda tidak terbatas pada byte atau kata tetapi dapat membalikkan jumlah bit yang berubah-ubah.HTH
sumber
std::vector<bool> b = { ... }; std::vector<bool> rb ( b.rbegin(), b.rend());
- menggunakan iterator terbalik secara langsung?Untuk kasus yang sangat terbatas dari input 8-bit yang konstan, metode ini tidak memerlukan biaya memori atau CPU pada saat run-time:
Saya menggunakan ini untuk ARINC-429 di mana urutan bit (endianness) label berlawanan dengan kata lainnya. Label seringkali konstan, dan biasanya dalam oktal.
Inilah cara saya menggunakannya untuk mendefinisikan sebuah konstanta, karena spesifikasi mendefinisikan label ini sebagai oktal 205 big-endian.
Contoh lainnya:
sumber
Ada banyak cara untuk membalikkan bit tergantung pada apa yang Anda maksud dengan "cara termudah".
Terbalik dengan Rotasi
Mungkin yang paling logis, terdiri dari memutar byte sambil menerapkan mask pada bit pertama
(n & 1)
:1) Karena panjang unsigner char adalah 1 byte, yang sama dengan 8 bit, berarti kita akan memindai setiap bit
while (byte_len--)
2) Pertama-tama kami memeriksa apakah b sedikit di ekstrem kanan dengan
(b & 1)
; jika demikian kita set bit 1 pada r dengan|
dan pindahkan hanya 1 bit ke kiri dengan mengalikan r dengan 2 dengan(r << 1)
3) Kemudian kita membagi unsigned char b dengan 2 dengan
b >>=1
untuk menghapus bit yang terletak di paling kanan dari variabel b. Sebagai pengingat, b >> = 1; setara dengan b / = 2;Terbalik dalam Satu Baris
Solusi ini dikaitkan dengan Rich Schroeppel di bagian Programming Hacks
1) Operasi penggandaan (b * 0x0202020202ULL) membuat lima salinan terpisah dari pola byte 8-bit untuk menyebar ke nilai 64-bit.
2) Operasi AND (& 0x010884422010ULL) memilih bit yang berada pada posisi yang benar (terbalik), relatif terhadap setiap grup bit 10-bit.
3) Bersama-sama operasi perkalian dan operasi AND menyalin bit dari byte asli sehingga masing-masing hanya muncul di salah satu dari set 10-bit. Posisi bit yang dibalik dari byte asli bertepatan dengan posisi relatifnya dalam set 10-bit.
4) Langkah terakhir (% 0x3ff), yang melibatkan pembagian modulus oleh 2 ^ 10 - 1 memiliki efek penggabungan bersama setiap set 10 bit (dari posisi 0-9, 10-19, 20-29, ...) dalam nilai 64-bit. Mereka tidak tumpang tindih, jadi langkah penjumlahan yang mendasari pembagian modulus berperilaku seperti operasi OR.
Bagi dan Taklukkan Solusi
Ini adalah jawaban yang paling banyak dipilih dan meskipun ada beberapa penjelasan, menurut saya bagi kebanyakan orang terasa sulit untuk memvisualisasikan arti sebenarnya dari 0xF0, 0xCC, 0xAA, 0x0F, 0x33 dan 0x55.
Itu tidak memanfaatkan '0b' yang merupakan ekstensi GCC dan disertakan sejak standar C ++ 14, dirilis pada Desember 2014, jadi beberapa saat setelah jawaban ini berasal dari April 2010
Silakan periksa cuplikan kode di bawah ini untuk mengingat dan memahami lebih baik solusi ini di mana kami bergerak setengah demi setengah:
NB: Itu
>> 4
karena ada 8 bit dalam 1 byte, yang merupakan karakter unsigned jadi kami ingin mengambil setengah lainnya, dan seterusnya.Kami dapat dengan mudah menerapkan solusi ini ke 4 byte dengan hanya dua baris tambahan dan mengikuti logika yang sama. Karena kedua topeng saling melengkapi, kita bahkan dapat menggunakan ~ untuk mengganti bit dan menghemat beberapa tinta:
[C ++ Only] Reverse Any Unsigned (Template)
Logika di atas dapat diringkas dengan loop yang akan bekerja pada semua jenis unsigned:
Cobalah sendiri dengan memasukkan fungsi di atas:
Membalik dengan asm volatile
Last but not least, jika yang paling sederhana berarti lebih sedikit baris, mengapa tidak mencoba perakitan inline?
Anda dapat menguji potongan kode di bawah ini dengan menambahkan
-masm=intel
saat menyusun:Penjelasan baris demi baris:
sumber
Pencarian tabel atau
edit
Lihat di sini untuk solusi lain yang mungkin bekerja lebih baik untuk Anda
sumber
implementasi yang lebih lambat tetapi lebih sederhana:
sumber
Bisakah ini menjadi solusi cepat?
Singkirkan kesibukan menggunakan for loop! tetapi para ahli tolong beri tahu saya apakah ini efisien dan lebih cepat?
sumber
Sebelum menerapkan solusi algoritmik apa pun, periksa bahasa assembly untuk arsitektur CPU apa pun yang Anda gunakan. Arsitektur Anda mungkin menyertakan instruksi yang menangani manipulasi bitwise seperti ini (dan apa yang bisa lebih sederhana dari instruksi perakitan tunggal?).
Jika instruksi seperti itu tidak tersedia, maka saya akan menyarankan untuk pergi dengan rute tabel pencarian. Anda dapat menulis skrip / program untuk membuat tabel untuk Anda, dan operasi pencarian akan lebih cepat daripada algoritma pembalikan bit mana pun di sini (dengan biaya harus menyimpan tabel pencarian di suatu tempat).
sumber
Fungsi sederhana ini menggunakan mask untuk menguji setiap bit dalam byte masukan dan mentransfernya menjadi keluaran bergeser:
sumber
Satu ini didasarkan pada salah satu BobStein-VisiBone disediakan
Saya sangat menyukai yang ini karena kompilator secara otomatis menangani pekerjaan untuk Anda, sehingga tidak memerlukan sumber daya lebih lanjut.
ini juga dapat diperpanjang hingga 16-Bit ...
sumber
b
in dalam tanda kurung jika itu adalah ekspresi yang lebih kompleks daripada satu angka, dan mungkin juga mengganti nama makro menjadiREVERSE_BYTE
sebagai petunjuk bahwa Anda mungkin tidak ingin memiliki ekspresi (runtime) yang lebih kompleks di sana. Atau jadikan sebagai fungsi sebaris. (Tapi secara keseluruhan saya suka ini karena cukup sederhana sehingga Anda dapat melakukannya dari memori dengan mudah dengan kemungkinan kesalahan yang sangat kecil.)Dengan asumsi bahwa compiler Anda mengizinkan unsigned long long :
Ditemukan di sini
sumber
Jika Anda menggunakan mikrokontroler kecil dan membutuhkan solusi kecepatan tinggi dengan footprint kecil, ini bisa menjadi solusi. Dimungkinkan untuk menggunakannya untuk proyek C, tetapi Anda perlu menambahkan file ini sebagai file assembler * .asm, ke proyek C Anda. Instruksi: Dalam proyek C tambahkan deklarasi ini:
Panggil fungsi ini dari C
Ini adalah kode, hanya cocok untuk inti 8.051. Dalam register CPU r0 adalah data dari byteInput . Kode rotate right r0 cross carry lalu putar carry kiri ke r1 . Ulangi prosedur ini 8 kali, untuk setiap bit. Kemudian register r1 dikembalikan ke c berfungsi sebagai byteOutput. Pada 8051 inti hanya dimungkinkan untuk memutar akumulator a .
PROS: Ini adalah tapak kecil, ini adalah kecepatan tinggi CONS: Ini bukan kode yang dapat digunakan kembali, ini hanya untuk 8.051
011101101-> bawa
101101110 <-membawa
sumber
byte terbalik akan berada di register bl
sumber
sumber
uint8_t
untuk bidang 1-bit agak jelek, karena tampaknya pertama kali mengatakan bahwa itu akan memakan waktu 8 bit tetapi kemudian di akhir baris mendefinisikannya hanya sebagai satu bit. Saya akan menggunakanunsigned b0:1
dll.sumber
Saya rasa ini cukup sederhana
atau
sumber
sumber
Saya akan chip dalam solusi saya, karena saya tidak dapat menemukan yang seperti ini dalam jawaban sejauh ini. Ini mungkin sedikit overengineered, tetapi menghasilkan tabel lookup menggunakan C ++ 14
std::index_sequence
dalam waktu kompilasi.https://godbolt.org/z/cSuWhF
sumber
Berikut adalah solusi sederhana dan dapat dibaca, portabel untuk semua platform yang sesuai, termasuk yang memiliki
sizeof(char) == sizeof(int)
:sumber
Saya tahu bahwa pertanyaan ini kuno, tetapi saya masih berpikir bahwa topik tersebut relevan untuk beberapa tujuan, dan ini adalah versi yang berfungsi dengan sangat baik dan dapat dibaca. Saya tidak bisa mengatakan bahwa ini adalah yang tercepat atau paling efisien, tetapi harus menjadi salah satu yang terbersih. Saya juga menyertakan fungsi helper untuk menampilkan pola bit dengan mudah. Fungsi ini menggunakan beberapa fungsi pustaka standar daripada menulis manipulator bit Anda sendiri.
Dan itu memberikan hasil sebagai berikut.
sumber
Yang ini membantu saya dengan set array 8x8 dot matrix.
sumber