Kapan tepat menggunakan operator bitwise dalam ekspresi bersyarat?

15

Pertama, beberapa latar belakang: Saya seorang guru IT dalam pelatihan dan saya mencoba memperkenalkan operator boolean java ke kelas 10 saya. Guru-mentor saya memeriksa lembar kerja yang saya siapkan dan berkomentar bahwa saya bisa membiarkan mereka menggunakan hanya satu & atau | untuk menunjukkan operator, karena mereka "melakukan hal yang sama".

Saya menyadari perbedaan antara & dan &&.
& adalah operator bitwise yang dimaksudkan untuk digunakan di antara bilangan bulat, untuk melakukan "bit-twiddling".
&& adalah operator kondisional yang dimaksudkan untuk digunakan di antara nilai-nilai boolean.

Untuk membuktikan bahwa operator ini tidak selalu "melakukan hal yang sama", saya mencari contoh di mana menggunakan bitwise antara nilai boolean akan menyebabkan kesalahan. Saya menemukan contoh ini

boolean bitwise;
boolean conditional;
int i=10, j=12;
bitwise = (i<j) | ((i=3) > 5); // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i<j) || (i=3) > 5 ;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);
i=10; 
bitwise = (i>j) & (i=3) > 5;   // value of i after oper: 3
System.out.println(bitwise+ " "+ i);
i=10; 
conditional = (i>j) && (i=3) > 5;  // value of i after oper: 10
System.out.println(conditional+ " "+ i);

Contoh ini menunjukkan bahwa jika suatu nilai harus diubah oleh bagian kedua dari ekspresi, ini akan menyebabkan perbedaan antara hasil, karena bitwise adalah operator yang bersemangat, sedangkan kondisional berperilaku sebagai hubungan pendek (tidak mengevaluasi yang kedua setengah, jika setengah pertama salah dalam kasus && dan benar dalam kasus ||).

Saya punya masalah dengan contoh ini. Mengapa Anda ingin mengubah nilai pada saat yang sama dengan melakukan perbandingan? Sepertinya bukan cara yang kuat untuk kode. Saya selalu enggan melakukan beberapa operasi dalam satu baris dalam kode produksi saya. Sepertinya sesuatu yang "koboi pengkodean" tanpa hati nurani akan pemeliharaan kode-nya. Saya tahu bahwa dalam beberapa kode domain harus sepadat mungkin, tetapi tentunya ini adalah praktik yang buruk pada umumnya?

Saya dapat menjelaskan pilihan saya untuk mendorong penggunaan && dan || lebih & dan | karena ini adalah konvensi pengkodean yang diterima dalam rekayasa perangkat lunak .

Tetapi bisakah seseorang tolong beri saya contoh yang lebih baik, bahkan di dunia nyata, menggunakan operator bitwise dalam ekspresi bersyarat?

Deerasha
sumber

Jawaban:

16

itu sesuai ketika Anda melakukan operasi masking

if ((a & b)> 0) {...}

di mana a dan b adalah bilangan bulat

|| dan | dan && dan & tidak dapat dipertukarkan

| dan & tidak akan pernah muncul dalam ekspresi kondisional sendiri (poin dari tautan yang Anda masukkan adalah bahwa hal-hal seperti itu paling sering kesalahan)

EDIT: Jangan berdebat dengan mentor Anda; bahkan jika Anda menang, Anda kalah. Sebaliknya, jelaskan bahwa Anda tidak ingin membingungkan siswa dengan menggabungkan operator logis dan operator bitwise dalam pelajaran yang sama. Anda bisa menjelaskan bahwa jika i = 3 dan j = 2 maka i & j = 2, sedangkan i && j adalah kesalahan. Namun, penjelasan yang lebih sederhana adalah bahwa Anda mengajar operator boolean (logis), jadi melempar bitwise setara kasus khusus adalah gangguan dari titik utama pelajaran. Tidak perlu membuat mentor "salah", dan tidak perlu menghasilkan contoh tandingan. Fokus pelajaran adalah pada operator boolean, bukan operator bitwise.

Sebagai akibat wajar, ketika Anda mulai mengajar operator bitwise, tidak perlu menunjukkan kasus khusus di mana + dan - menghasilkan hasil yang sama dengan & dan |

Steven A. Lowe
sumber
Kode di atas tidak salah, mungkin membingungkan tetapi karena kode itu tidak mengandung kesalahan, bukan? Saya setuju bahwa menggunakan operator bitwise dengan cara ini tidak terlalu mudah dibaca, saya tidak akan suka jika saya melihatnya dalam ulasan kode, tetapi itu adalah Java legal (dan C # juga, mengabaikan System.out.println).
Steve
Terima kasih telah menjawab @Steven A. Lowe. Anda mengatakan "|| dan | dan && dan & tidak dapat dipertukarkan" tetapi bitwise = !(true & true == false);dan condition = !(true && true == false);akan sama-sama mengevaluasi menjadi benar, jadi dalam hal ini keduanya dapat dipertukarkan? Mungkin secara sintaksis, karena kode masih dikompilasi. Saya setuju bahwa mereka digunakan untuk hal-hal yang berbeda secara semantik, seperti yang saya sebutkan pada paragraf 2. Anda mengatakan itu! dan & "hampir tidak pernah muncul dalam kondisi sendiri". Saya mencari kasus-kasus "hampir tidak pernah" ini, dan bertanya-tanya apakah mereka benar-benar ada.
Deerasha
@ Deerasha: || dan && hanya beroperasi di boolean. & dan | beroperasi pada bilangan bulat dan boolean - ada sedikit gunanya menggunakan operator bitwise (dimaksudkan untuk beroperasi pada beberapa bit ) untuk memanipulasi boolean, dan melakukannya dengan ditinggalkan dapat menyebabkan kode membingungkan dan perilaku tak terduga (yaitu jika Anda secara tidak sengaja menggunakan integer alih-alih sebuah boolean, operator bitwise tidak akan mengeluh)
Steven A. Lowe
Ya @Steve Haigh, kompiler tidak menolaknya, tapi itu bukan cara yang tepat untuk menggunakannya, dilihat dari standar pengkodean yang diterbitkan yang saya tautkan. Dapatkah saya beristirahat dengan nyaman mengabaikannya karena tidak memenuhi standar pengkodean, atau haruskah java menunjukkan bahwa ini adalah penggunaan yang tidak tepat?
Deerasha
2
@ Seven A. Lowe: jika i = 3 dan j = 2 maka i & j = 2, sedangkan i && j adalah kesalahan Ini brilian! Ini sederhana dan itu yang penting. Pada tingkat kelas 10, ini juga kemungkinan kesalahan, karena mereka masih terbiasa dengan tipe Boolean dan apa yang akan diterapkan oleh operator. Terima kasih banyak! Saran bagus untuk tidak berdebat dengan mentor saya juga.
Deerasha
12

Operator non-bitwise &&dan ||merupakan operator hubung singkat. Dengan kata lain, dengan &&, jika LHS salah, RHS tidak akan pernah dievaluasi; dengan ||jika LHS benar, maka RHS tidak akan pernah dievaluasi. Di sisi lain, operator bitwise &dan |non-korsleting, dan akan selalu mengevaluasi LHS dan RHS. Kalau tidak, mereka setara dalam sebuah ifpernyataan.

Satu-satunya waktu saya dapat melihat nilai dalam menggunakan operator non-hubung singkat adalah jika RHS memiliki semacam efek samping yang diinginkan yang Anda inginkan terjadi dalam semua kasus. Saya tidak dapat memikirkan contoh spesifik di mana Anda menginginkan ini, dan saya tidak percaya itu adalah praktik yang baik, tetapi itulah bedanya.

Jonathan
sumber
1
+1. Tepat sekali, ketika membandingkan boolean bitwise dan operator logika selalu mengembalikan hasil yang sama, tetapi (di Jawa dan C # setidaknya) hanya hubungan pendek operator logis.
Steve
Terima kasih telah menjawab. Paragraf 1 Anda adalah apa yang saya coba sampaikan pada paragraf 4 saya, dengan menyatakan bahwa bitwise adalah operator yang bersemangat sementara kondisional berperilaku sebagai hubungan pendek . Paragraf 2 Anda adalah keprihatinan yang saya jelaskan dalam paragraf 5. Jadi saya menyadari perbedaannya, tetapi saya mencari contoh spesifik yang tidak dapat Anda maupun saya pikirkan.
Deerasha
7

Jawaban filosofis umum adalah bahwa menggunakan operator bitwise untuk operator boolean tidak lazim dan membuat kode lebih sulit dibaca. Dalam prakteknya (untuk kode yang ada dalam produksi), kode yang lebih mudah dibaca lebih mudah dipelihara dan dengan demikian lebih diinginkan.

Untuk penggunaan di dunia nyata dari kebutuhan akan operator hubungan pendek, lihat kasus-kasus seperti:

if (args.length > 0 && args[0] == 'test') ....

if (b != NULL && b.some_function()) ...

if (b == NULL || b.some_function()) ...

Jenis operasi ini sering muncul dalam kode dunia nyata.

Kathy Van Stone
sumber
Tfa. Bagaimana saya menjelaskan kepada anak-anak 15 tahun saya bahwa 1 &“lebih sulit dibaca” daripada 2? Saya tidak punya contoh di mana 2 operator tidak bekerja dengan cara yang sama untuk operan Boolean. Saya menyetujui poin Anda tentang kode yang lebih mudah dibaca dan lebih mudah dikelola. Saya ingin mendorong mereka untuk menulis kode yang indah. Tetapi memiliki beberapa bukti di tas alat saya akan lebih meyakinkan daripada "karena saya bilang begitu". Saya sudah menyatakannya sebagai standar pada tautan itu, dan mungkin harus mengandalkan itu sendiri jika saya tidak mendapatkan contoh yang saya cari. Seperti yang saya tanyakan pada @Steve Haigh: haruskah java menunjukkan ini sebagai penggunaan yang tidak tepat?
Deerasha
@ Dashaasha saya lebih memikirkan pertengkaran dengan mentor Anda. Untuk kelas bahkan tidak mencoba memberi tahu mereka bahwa Anda dapat menggunakan operator bitwise untuk kondisi logis.
Kathy Van Stone
4

Anda akan menggunakan operator bitwise jika Anda membandingkan enumerasi Bitmask. Misalnya, Anda memiliki penghitungan status dan objek yang bisa berada di lebih dari satu status tersebut. Dalam hal ini, Anda akan melakukan bitwise atau untuk menetapkan lebih dari satu status ke objek Anda.

misalnya state = CONNECTED | IN_PROGRESSdimana CONNECTED could be 0x00000001danIN_PROGRESS 0x00000010

Untuk info lebih lanjut, lihat dokumentasi flag enums.

pwny
sumber
Terima kasih kepada Anda, saya telah mempelajari aplikasi operator bitwise yang belum saya ketahui sebelumnya! Tetapi dalam contoh ini, hanya operator bitwise yang berlaku. Saya mencari sepotong kode yang ditulis dengan baik di mana menggunakan bitwise daripada kondisional akan mengarah pada kompilasi, tetapi output yang salah. Yaitu, jika potongan kode seperti itu ada.
Deerasha
Saya tidak berpikir ini bisa terjadi di Jawa karena saya percaya memanggil | atau & operator pada nilai-nilai yang tidak bisa bitwise dan akan atau atau hanya melakukan logika | atau &. Saya tidak ingat apakah ini yang terjadi di Jawa, tetapi tahu pasti di C # MSDN: "Binary | operator sudah ditentukan untuk tipe integral dan bool. Untuk tipe integral, | menghitung bitwise ATAU operandnya. Untuk operan bool, | menghitung logika ATAU
operannya
Setelah beberapa penelitian lebih lanjut, saya menemukan bahwa satu-satunya perbedaan antara | dan || dan & dan && untuk operan boolean di Jawa adalah perilaku hubungan pendek sehingga skenario yang Anda gambarkan tidak benar-benar mungkin.
pwny
0

contoh sederhana kesalahan:

int condA=1, condB=2;

if (condA!=0 && condB!=0) {
    // correct!
}
if ((condA & condB)!=0) {
    // never executed
}

di sini Anda memiliki dua kondisi, keduanya bukan nol; tetapi &hasil bitwise dalam nol.

Javier
sumber
@Javier: Terima kasih telah menjawab, tapi saya agak bingung. Saya bekerja di java, dan kode ini tidak dapat dikompilasi. (condA && condB)kesalahan, karena && tidak berfungsi selama 2 intdetik, hanya 2 boolean. (condA & condB)sementara benar, mengevaluasi ke int dan di java kita tidak bisa mengatakannya if(int)juga kesalahan. Anda adalah orang pertama yang memahami apa yang saya cari - persis contoh kesalahan itu .
Deerasha
belum pernah menggunakan Java dalam waktu yang lama ... coba (Boolean(condA) && Boolean(condB)) (saya pikir Boolean(x)ini trueuntuk bilangan bulat bukan nol, kan?)
Javier
Nggak @Javier: Tidak bisa berpindah dari int ke boolean.
Deerasha
bagaimana ((condA!=0) && (condB!=0))?
Javier
@Javier yay mengkompilasi, tetapi "kesalahan" tidak lagi diilustrasikan if (((condA!=0) && (condB!=0))) { System.out.println("correct"); } if (((condA!=0) & (condB!=0))) { System.out.println("never executed?"); }mengeksekusi kedua pernyataan cetak.
Deerasha