Quando è appropriato usare un operatore bit a bit in un'espressione condizionale?


15

In primo luogo, alcuni retroscena: sono un insegnante in formazione IT e sto cercando di introdurre gli operatori booleani di Java alla mia classe di 10 ° grado. Il mio insegnante-mentore ha esaminato un foglio di lavoro che ho preparato e ha commentato che potevo lasciarli usare solo un singolo & o | per indicare gli operatori, perché "fanno la stessa cosa".

Sono consapevole della differenza tra & e &&.
& è un operatore bit a bit destinato all'uso tra numeri interi, per eseguire "bit-twiddling".
&& è un operatore condizionale destinato all'uso tra valori booleani.

Per dimostrare che questi operatori non sempre "fanno la stessa cosa", ho deciso di trovare un esempio in cui l'uso del bitwise tra valori booleani comporterebbe un errore. Ho trovato questo esempio

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

Questo esempio mostra che se un valore deve essere modificato dalla seconda metà dell'espressione, ciò porterebbe a una differenza tra i risultati, poiché bit a bit è un operatore desideroso, mentre il condizionale si comporta come un cortocircuito (non valuta la seconda metà, se la prima metà è falsa nel caso di && e vera nel caso di ||).

Ho un problema con questo esempio. Perché dovresti cambiare un valore contemporaneamente a un confronto su di esso? Non sembra un modo robusto per codificare. Sono sempre stato contrario a fare più operazioni in una sola riga nel mio codice di produzione. Sembra qualcosa che farebbe un "cowboy in codice" senza coscienza per quanto riguarda la manutenibilità del suo codice. So che in alcuni domini il codice deve essere il più compatto possibile, ma sicuramente questa è una cattiva pratica in generale?

Posso spiegare la mia scelta di incoraggiare l'uso di && e || oltre & e | perché questa è una convenzione di codifica accettata nell'ingegneria del software .

Ma qualcuno potrebbe darmi un esempio migliore, persino reale, dell'uso di un operatore bit per bit in un'espressione condizionale?

Risposte:


16

è appropriato quando si esegue un'operazione di mascheramento

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

dove aeb sono numeri interi

|| e | e && e & non sono intercambiabili

| e non compariranno mai in un'espressione condizionale da soli (il punto del collegamento che hai incluso è che spesso queste cose sono errori)

EDIT: non discutere con il tuo mentore; anche se vinci, perdi. Spiega invece che non vuoi confondere gli studenti mescolando operatori logici e operatori bit a bit nella stessa lezione. Potresti spiegare che se i = 3 e j = 2 allora i & j = 2, mentre i && j è un errore. Tuttavia, la spiegazione più semplice è che stai insegnando agli operatori booleani (logici), quindi inserire equivalenti bit per bit in casi speciali è una distrazione dal punto principale della lezione. Non è necessario rendere il mentore "sbagliato" e non è necessario produrre contro-esempi. Il focus della lezione è sugli operatori booleani, non sugli operatori bit a bit.

Come corollario, quando inizi a insegnare agli operatori bit a bit, non è necessario mostrare i casi speciali in cui + e - producono gli stessi risultati di & e |


Il codice sopra non è sbagliato, può essere fonte di confusione ma com'è che quel codice non contiene un errore, vero? Sono d'accordo che l'utilizzo degli operatori bit per bit in questo modo non è molto leggibile, non mi piacerebbe se lo vedessi in una revisione del codice, ma è Java legale (e anche C #, ignorando System.out.println).
Steve,

Grazie per aver risposto a @Steven A. Lowe. Lei ha detto "|| e | e && e & non sono intercambiabili", ma bitwise = !(true & true == false);e condition = !(true && true == false);saranno entrambi valutata come vera, quindi in questo caso sono intercambiabili? Sintatticamente, forse, poiché il codice viene ancora compilato. Concordo sul fatto che sono usati semanticamente per cose diverse, come ho detto nel paragrafo 2. Lo dici tu! e & "quasi mai apparire in un condizionale da soli". Sto cercando questi casi "quasi mai" e mi chiedo se esistano legittimamente.
Deerasha,

@Deerasha: || e && operano solo su valori booleani. & e | operare su numeri interi e booleani - non ha senso usare operatori bit a bit (destinati a operare su più bit ) per manipolare i valori booleani, e farlo con abbandono può portare a confondere codice e comportamenti imprevisti (ad esempio se si utilizza accidentalmente un numero intero anziché un booleano, gli operatori bit per bit non si lamenteranno)
Steven A. Lowe,

Sì @Steve Haigh, il compilatore non lo rifiuta, ma non è il modo giusto di usarli, a giudicare dallo standard di codifica pubblicato che ho collegato. Posso tranquillamente riposare sul licenziarlo perché non è conforme a uno standard di codifica o Java dovrebbe forse indicare che si tratta di un uso improprio?
Deerasha,

2
@Steven A. Lowe: se i = 3 e j = 2 allora i & j = 2, mentre i && j è un errore Questo è geniale! È semplice e fa il punto. Al decimo livello anche questo è probabilmente un errore, dato che si stanno ancora abituando al tipo booleano e a cosa si applicherebbero gli operatori. Grazie mille! Ottimo consiglio di non discutere con il mio mentore.
Deerasha,

12

Gli operatori non bit per bit &&e ||sono operatori di corto circuito. In altre parole, con &&, se l'LHS è falso, l'RHS non verrà mai valutato; con ||se il LHS è vero, allora il RHS sarà mai valutato. D'altra parte, gli operatori bit a bit &e |sono non in corto circuito, e valuteranno sempre sia l'LHS che l'RHS. Altrimenti, sono equivalenti in una ifdichiarazione.

L'unica volta in cui riesco a vedere un valore nell'uso degli operatori non in cortocircuito è se l'RHS ha qualche tipo di effetto collaterale desiderabile che si desidera che si verifichi in tutti i casi. Non riesco a pensare a un esempio specifico in cui lo vorresti, e non credo che sia una buona pratica, ma questa è la differenza.


1
+1. Esatto, quando si confrontano i valori booleani bit per bit e gli operatori logici restituiscono sempre lo stesso risultato, ma (almeno in Java e C #) solo il cortocircuito degli operatori logici.
Steve,

Grazie per avermi risposto. Il tuo paragrafo 1 era quello che stavo cercando di ottenere nel mio paragrafo 4, affermando che bit a bit è un operatore desideroso mentre il condizionale si comporta come un corto circuito . Il tuo paragrafo 2 è la preoccupazione che ho descritto nel mio paragrafo 5. Quindi sono consapevole della differenza ma sto cercando quell'esempio specifico che né tu né io possiamo pensare.
Deerasha,

7

La risposta filosofica generale è che l'uso di operatori bit per bit per operatori booleani è atipico e rende il codice più difficile da leggere. In pratica (per il codice in produzione), un codice più leggibile è più facile da mantenere e quindi più desiderabile.

Per un uso nel mondo reale della necessità di operatori di cortocircuito, vedere casi come:

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

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

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

Questo tipo di operazioni si presentano frequentemente nel codice del mondo reale.


TFA. Come faccio a spiegare ai miei 15 anni che 1 &è "più difficile da leggere" di 2? Non ho un esempio in cui i 2 operatori non funzionino allo stesso modo per gli operandi booleani. Concordo sul tuo punto in merito a un codice più leggibile e più facile da mantenere. Voglio incoraggiarli a scrivere un bellissimo codice. Ma avere qualche prova nella mia borsa degli strumenti sarebbe più convincente di "perché l'ho detto". Ho dichiarato come standard a quel link, e potrebbe essere necessario fare affidamento solo su questo se non ottengo l'esempio che sto cercando. Come ho chiesto a @Steve Haigh: java dovrebbe indicare questo come un uso improprio?
Deerasha,

@Deerasha Stavo pensando più a una discussione con il tuo mentore. Per la classe non provare nemmeno a dire loro che puoi usare operatori bit a bit per condizioni logiche.
Kathy Van Stone,

4

Utilizzerai operatori bit per bit se confronti le enumerazioni della maschera di bit. Ad esempio, hai un elenco di stati e un oggetto che può trovarsi in più di uno di quegli stati. In questo caso, eseguirai un'operazione bit a bit o per assegnare più di uno stato al tuo oggetto.

per esempio state = CONNECTED | IN_PROGRESSdove CONNECTED could be 0x00000001eIN_PROGRESS 0x00000010

Per ulteriori informazioni, consultare la documentazione di enum flag.


Grazie a te ho imparato un'applicazione di operatori bit per bit che non conoscevo prima! Ma in questo esempio si applica solo l'operatore bit a bit. Sto cercando un pezzo di codice ben scritto in cui l'uso del bit per bit anziché del condizionale porterebbe alla compilazione, ma un output errato. Cioè, se esiste un tale frammento di codice.
Deerasha,

Non penso che ciò possa accadere in Java come credo chiamare | o & operatori su valori che non possono essere bit per bit e che eseguono o hanno semplicemente un logico | o &. Non riesco a ricordare se questo è il caso in Java, ma so per certo che è in MSDN C #: "Gli operatori binari | sono predefiniti per i tipi integrali e bool. Per i tipi integrali | calcola l'OR bit a bit dei suoi operandi. bool operandi, | calcola l'OR logico dei suoi operandi "
pwny

Dopo qualche altra ricerca, ho scoperto che l'unica differenza tra | e || e & and && per operandi booleani in Java è il comportamento in corto circuito, quindi lo scenario che stai descrivendo non è davvero possibile.
pwny

0

un esempio più semplice di errore:

int condA=1, condB=2;

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

qui hai due condizioni, entrambe sono diverse da zero; ma bit &a bit si traduce in zero.


@Javier: Grazie per aver risposto, ma sono un po 'confuso. Sto lavorando in Java e questo codice non viene compilato. (condA && condB)errori, perché && non funziona per 2 intsecondi, solo 2 valori booleani. (condA & condB)benché corretto, restituisce an int e in java non possiamo dire if(int)quindi anche errori. Sei il primo a capire cosa sto cercando, esattamente quell'esempio di errore .
Deerasha,

non uso Java da molto tempo ... prova (Boolean(condA) && Boolean(condB)) (penso Boolean(x)sia trueper numeri interi diversi da zero, giusto?)
Javier

No @Javier: impossibile eseguire il cast da int a booleano.
Deerasha,

che dire ((condA!=0) && (condB!=0))?
Javier,

@Javier yay si compila, ma "l'errore" non è più illustrato if (((condA!=0) && (condB!=0))) { System.out.println("correct"); } if (((condA!=0) & (condB!=0))) { System.out.println("never executed?"); }esegue entrambe le istruzioni di stampa.
Deerasha,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.