Khi nào thì thích hợp sử dụng toán tử bitwise trong biểu thức điều kiện?


15

Đầu tiên, một số nền tảng: Tôi là một giáo viên đào tạo CNTT và tôi đang cố gắng giới thiệu các toán tử boolean của java cho lớp 10 của tôi. Giáo viên cố vấn của tôi đã xem qua một bảng tính mà tôi đã chuẩn bị và nhận xét rằng tôi có thể cho phép họ sử dụng chỉ một & & | để biểu thị các toán tử, bởi vì họ "làm điều tương tự".

Tôi nhận thức được sự khác biệt giữa & và &&.
& là một toán tử bitwise dự định sử dụng giữa các số nguyên, để thực hiện "twiddling".
&& là toán tử có điều kiện dành cho sử dụng giữa các giá trị boolean.

Để chứng minh điểm mà các toán tử này không phải lúc nào cũng "làm điều tương tự", tôi đặt ra để tìm một ví dụ trong đó sử dụng bitwise giữa các giá trị boolean sẽ dẫn đến lỗi. Tôi tìm thấy ví dụ này

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);

Ví dụ này cho thấy rằng nếu một giá trị phải được thay đổi bởi nửa sau của biểu thức, thì điều này sẽ dẫn đến sự khác biệt giữa các kết quả, vì bitwise là một toán tử háo hức, trong khi điều kiện hoạt động như một mạch ngắn (không đánh giá thứ hai một nửa, nếu nửa đầu là sai trong trường hợp && và đúng trong trường hợp | |).

Tôi có một vấn đề với ví dụ này. Tại sao bạn muốn thay đổi một giá trị cùng lúc với việc bạn so sánh nó? Nó dường như không phải là một cách mạnh mẽ để viết mã. Tôi luôn không thích thực hiện nhiều thao tác trong một dòng trong mã sản xuất của mình. Có vẻ như một thứ gì đó là "cao bồi mã hóa" không có lương tâm về khả năng duy trì mã của anh ta sẽ làm. Tôi biết rằng trong một số tên miền mã cần phải gọn nhất có thể, nhưng chắc chắn đây là một thực tế kém nói chung?

Tôi có thể giải thích sự lựa chọn của mình về việc khuyến khích sử dụng && và || trên & và | bởi vì đây là một quy ước mã hóa được chấp nhận trong công nghệ phần mềm .

Nhưng ai đó có thể vui lòng cho tôi một ví dụ tốt hơn, thậm chí trong thế giới thực, về việc sử dụng toán tử bitwise trong biểu thức điều kiện không?

Câu trả lời:


16

nó phù hợp khi bạn đang thực hiện thao tác mặt nạ

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

trong đó a và b là số nguyên

| | và | và && và & không thể hoán đổi cho nhau

| và & amost sẽ không bao giờ xuất hiện trong một biểu thức có điều kiện (điểm liên kết bạn đưa vào là những thứ như vậy thường là lỗi nhất)

EDIT: Đừng tranh luận với người cố vấn của bạn; ngay cả khi bạn thắng, bạn vẫn thua. Thay vào đó, giải thích rằng bạn không muốn gây nhầm lẫn cho sinh viên bằng cách trộn các toán tử logic và toán tử bitwise trong cùng một bài học. Bạn có thể giải thích rằng nếu i = 3 và j = 2 thì i & j = 2, trong khi i && j là một lỗi. Tuy nhiên, lời giải thích đơn giản hơn là bạn đang dạy các toán tử boolean (logic), do đó, việc ném vào các trường hợp tương đương bitwise trong trường hợp đặc biệt là một sự phân tâm từ điểm chính của bài học. Không cần phải làm cho người cố vấn "sai", và không cần phải đưa ra các ví dụ phản tác dụng. Trọng tâm của bài học là về các toán tử boolean, không phải các toán tử bitwise.

Như một hệ quả tất yếu, khi bạn bắt đầu dạy các toán tử bitwise, không cần hiển thị các trường hợp đặc biệt trong đó + và - tạo ra kết quả giống như & và |


Mã ở trên không sai, mặc dù nó có thể gây nhầm lẫn nhưng vì mã đó không có lỗi phải không? Tôi đồng ý rằng việc sử dụng các toán tử bitwise theo cách này là không dễ đọc, tôi sẽ không thích nó nếu tôi thấy nó trong bài đánh giá mã, nhưng đó là Java hợp pháp (và C # cũng vậy, bỏ qua System.out.println).
Steve

Cảm ơn bạn đã trả lời @Steven A. Lowe. Bạn nói "|| và | và && và & không được hoán đổi" nhưng bitwise = !(true & true == false);condition = !(true && true == false);cả hai sẽ đánh giá đúng sự thật, vì vậy trong trường hợp này họ được hoán đổi? Cú pháp có lẽ, vì mã vẫn biên dịch. Tôi đồng ý rằng chúng được sử dụng cho những thứ khác nhau về mặt ngữ nghĩa, như tôi đã đề cập trong đoạn 2. Bạn nói vậy! và & "hầu như không bao giờ xuất hiện trong một điều kiện của chính họ". Tôi đang tìm kiếm những trường hợp "gần như không bao giờ" này, và tự hỏi liệu chúng có tồn tại hợp pháp không.
Deerasha

@Deerasha: || và && chỉ hoạt động trên booleans. và | hoạt động trên các số nguyên booleans - có rất ít điểm trong việc sử dụng các toán tử bitwise (dự định hoạt động trên nhiều bit ) để thao tác booleans và làm như vậy với việc từ bỏ có thể dẫn đến nhầm lẫn mã và các hành vi không mong muốn (ví dụ: nếu bạn vô tình sử dụng một số nguyên thay vì một số nguyên thay vì boolean, các nhà khai thác bitwise sẽ không phàn nàn)
Steven A. Lowe

Có @Steve Haigh, trình biên dịch không từ chối nó, nhưng đó không phải là cách đúng để sử dụng chúng, đánh giá từ tiêu chuẩn mã hóa được công bố mà tôi liên kết đến. Tôi có thể thoải mái nghỉ việc khi loại bỏ nó vì nó không tuân thủ một tiêu chuẩn mã hóa, hay java có thể chỉ ra rằng đây là một cách sử dụng không đúng?
Deerasha

2
@Steven A. Lowe: nếu i = 3 và j = 2 thì i & j = 2, trong khi i && j là một lỗi Điều này thật tuyệt vời! Nó đơn giản và nó làm cho vấn đề. Ở cấp lớp 10, đây cũng là một lỗi có thể xảy ra, vì chúng vẫn đang quen với loại Boolean và những gì các nhà khai thác sẽ áp dụng. Cảm ơn bạn rất nhiều! Lời khuyên tuyệt vời về việc không tranh luận với người cố vấn của tôi.
Deerasha

12

Các toán tử không bitwise &&||là các toán tử ngắn mạch. Nói cách khác, với &&, nếu LHS sai, RHS sẽ không bao giờ được đánh giá; với ||nếu LHS là đúng, thì RHS sẽ không bao giờ được đánh giá. Mặt khác, các toán tử bitwise &|không ngắn mạch, và sẽ luôn đánh giá cả LHS và RHS. Mặt khác, chúng tương đương trong một iftuyên bố.

Lần duy nhất tôi có thể thấy giá trị khi sử dụng các toán tử không ngắn mạch là nếu RHS có một loại tác dụng phụ mong muốn mà bạn muốn xảy ra trong mọi trường hợp. Tôi không thể nghĩ ra một ví dụ cụ thể nơi bạn muốn điều này và tôi không tin đó là cách thực hành tốt, nhưng đó là sự khác biệt.


1
+1. Chính xác, khi so sánh các toán tử booleans bit và toán tử logic luôn trả về cùng một kết quả, nhưng (ít nhất là trong Java và C #) chỉ các toán tử logic ngắn mạch.
Steve

Cảm ơn vì đã trả lời. Đoạn 1 của bạn là những gì tôi đã cố gắng đạt được trong đoạn 4 của mình, bằng cách nói rằng bitwise là một toán tử háo hức trong khi điều kiện hoạt động như một mạch ngắn . Đoạn 2 của bạn là mối quan tâm tôi đã mô tả trong đoạn 5. Vì vậy, tôi nhận thấy sự khác biệt nhưng tôi đang tìm kiếm ví dụ cụ thể đó mà cả bạn và tôi đều không thể nghĩ ra.
Deerasha

7

Câu trả lời triết học chung là việc sử dụng các toán tử bitwise cho các toán tử boolean là không điển hình và làm cho mã khó đọc hơn. Trong thực tế (đối với mã đang được sản xuất), mã dễ đọc hơn sẽ dễ bảo trì hơn và do đó mong muốn hơn.

Để sử dụng trong thế giới thực, cần có các toán tử ngắn mạch, xem các trường hợp như:

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

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

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

Những loại hoạt động này xuất hiện thường xuyên trong mã thế giới thực.


Tfa. Làm thế nào để tôi giải thích cho những đứa trẻ 15 tuổi của mình rằng 1 &là khó đọc hơn so với 2? Tôi không có một ví dụ trong đó 2 toán tử không hoạt động theo cùng một cách cho toán hạng Boolean. Tôi đồng ý với quan điểm của bạn về việc dễ đọc hơn và dễ dàng hơn để duy trì mã. Tôi muốn khuyến khích họ viết mã đẹp. Nhưng có một số bằng chứng trong túi công cụ của tôi sẽ thuyết phục hơn so với vì tôi đã nói như vậy. Tôi thực sự đã nêu nó như là một tiêu chuẩn tại liên kết đó và có thể phải dựa vào điều đó một mình nếu tôi không lấy ví dụ mà tôi đang tìm kiếm. Như tôi đã hỏi @Steve Haigh: java có nên chỉ ra điều này là sử dụng không đúng cách không?
Deerasha

@Deerasha Tôi đã suy nghĩ nhiều hơn về một cuộc tranh luận với người cố vấn của bạn. Đối với lớp thậm chí không cố gắng nói với họ rằng bạn có thể sử dụng các toán tử bitwise cho các điều kiện logic.
Kathy Van Stone

4

Bạn sẽ sử dụng các toán tử bitwise nếu bạn so sánh các liệt kê Bitmask. Ví dụ: bạn có một bảng liệt kê các trạng thái và một đối tượng có thể ở nhiều hơn một trong các trạng thái đó. Trong trường hợp này, bạn sẽ thực hiện một chút hoặc để gán nhiều trạng thái cho đối tượng của mình.

ví dụ như state = CONNECTED | IN_PROGRESSở đâu CONNECTED could be 0x00000001IN_PROGRESS 0x00000010

Để biết thêm thông tin, tra cứu tài liệu enums cờ.


Nhờ các bạn tôi đã học được một ứng dụng của các toán tử bitwise mà tôi chưa biết trước đây! Nhưng trong ví dụ này, chỉ áp dụng toán tử bitwise. Tôi đang tìm kiếm một đoạn mã được viết tốt trong đó sử dụng bitwise thay vì điều kiện sẽ dẫn đến việc biên dịch, nhưng đầu ra không chính xác. Đó là, nếu một đoạn mã như vậy tồn tại.
Deerasha

Tôi không nghĩ điều này có thể xảy ra trong Java vì tôi tin rằng việc gọi | hoặc & toán tử trên các giá trị không thể theo chiều bit và sẽ hoặc hoặc chỉ thực hiện logic | hoặc là &. Tôi không thể nhớ lại nếu đây là trường hợp trong Java, nhưng biết chắc chắn đó là trong C # MSDN: "Toán tử nhị phân | được xác định trước cho các kiểu tích phân và bool. Đối với các kiểu tích phân, | tính toán bitwise OR của toán hạng của nó. toán hạng bool, | tính toán logic HOẶC toán hạng của nó "
pwny

Sau một số nghiên cứu, tôi phát hiện ra rằng sự khác biệt duy nhất giữa | và || và & & & cho các toán hạng boolean trong Java là hành vi ngắn mạch nên kịch bản bạn mô tả không thực sự có thể xảy ra.
pwny

0

một ví dụ đơn giản hơn về sai lầm:

int condA=1, condB=2;

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

Ở đây bạn có hai điều kiện, cả hai đều khác không; nhưng &kết quả bitwise bằng không.


@Javier: Cảm ơn bạn đã trả lời, nhưng tôi hơi bối rối. Tôi đang làm việc trong java và mã này không biên dịch. (condA && condB)lỗi, vì && không hoạt động trong 2 intgiây, chỉ có 2 booleans. (condA & condB)trong khi chính xác, đánh giá một int và trong java chúng ta không thể nói if(int)như vậy nó cũng có lỗi. Bạn là người đầu tiên hiểu những gì tôi đang tìm kiếm - chính xác là ví dụ về sự sai trái .
Deerasha

đã không sử dụng Java trong một thời gian dài ... hãy thử (Boolean(condA) && Boolean(condB)) (tôi nghĩ Boolean(x)truedành cho các số nguyên khác không, phải không?)
Javier

Nope @Javier: Không thể chuyển từ int sang boolean.
Deerasha

những gì về ((condA!=0) && (condB!=0))?
Javier

@Javier yay nó biên dịch, nhưng "sai" không còn được minh họa if (((condA!=0) && (condB!=0))) { System.out.println("correct"); } if (((condA!=0) & (condB!=0))) { System.out.println("never executed?"); }thực thi cả hai câu lệnh in.
Deerasha
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.