2013-08-03 8 views
5

Bramka logiczna NAND dla dwóch warunków (A i B) to true, o ile dowolny warunek jest prawdziwy, lub żaden z warunków nie jest prawdziwy; i jest to , jeśli warunki są prawdziwe.Która jest bardziej wydajna składnia dla NAND (nie obie prawda) w C#?

F NAND F = T 
F NAND T = T 
T NAND F = T 
T NAND T = F 

W języku C# można napisać to w co najmniej dwa sposoby:

!(A && B) 

lub

(!A || !B) 

Który bardziej wydajne?

Wydaje mi się, że if(A), a następnie B jest zawsze testowany i if(!A), a następnie B nigdy nie jest testowany.

Ale wtedy pierwszy warunek musi odwrócić wynik ....

+0

odwrócenie wyniku jest tożsame z zamianą kodu w 'else' z kodem w' if' ... nie jest wymagana aktualna instrukcja runtime –

Odpowiedz

5

To nie jest takie proste. Język C# nie modeluje bramy NAND w ogóle za pomocą operatora & &. Ten operator ma zwarcie zachowanie, bardzo wygodne w programie C#.I powszechne zachowanie dla języków kręcone nawiasów, wyrażenie tak nie psuje swój kod:

arr[] = somefunction(); 
int ix = foo; 
if (ix < arr.Length && arr[ix] == 42) { 
    EmailBookRecommendation(); 
} 

Ale to bardzo nieefektywne wersja wypowiedzi, ten jest sposób bardziej wydajnych:

if (ix < arr.Length & arr [ix] == 42) 

Co jest doskonałym wyrażeniem prawnym, operator & działa dobrze z operandami logicznymi. Ale niestety to powoduje awarię twojego kodu. Oblicza wyrażenie indeksujące tablicę i idzie Kaboom! z IndexOutOfRangeException.

To nigdy nie jest problem z bramką NAND, nie ulega awarii, gdy pierwszym wejściem jest F :) Istnieje wiele możliwych wyrażeń , w których to nie jest problem. Naprawdę powinieneś faworyzować operatora &. To powoduje, że różnica jest ogromna. Więc zawsze napisz coś takiego:

if (ix >= 1 & ix <= 42) 

Co oczywiście nigdy nie zawiedzie. Aby zrozumieć, dlaczego operator & jest o wiele bardziej nieefektywny niż operator &, należy zrozumieć prognozę rozgałęzienia. Jest to bardzo dobrze opisane w this answer.

+0

W moim przypadku porównuję wartości całkowite z literałami. Więc jest to coś w stylu 'if (Foo.A == CONST1 NAND Foo.B == CONST2) {Bar();}' Tak więc mogłem z łatwością korzystać z "&" zamiast "&&" bez komplikacji proceduralnych lub spowolnienia. Jeśli dobrze Cię odczytam, bardziej wydajne jest używanie "&" i "przewidywanie" uzyskanego warunku? Nie jestem do końca pewien, czy podążam. – Matthew

+0

Poza tym (1) pytanie nie pytało o '&', a (2) '&&' nie jest "dużo bardziej nieefektywne niż operator' & '", to zależy całkowicie od wyrażeń związanych. –

+0

Czy możesz rozwinąć "ogromną różnicę"? – Piedone

1

Ani. Oba mają dokładnie takie samo działanie powodujące zwarcie, a kompilator zmieni oba na MSIL, żądając testu A, po którym następuje gałąź warunkowa. Oddział, w którym A był prawdziwy, będzie miał test B.

Co trzeba się martwić o to:

!(A && B) 

vs

!(B && A) 

które różnią się w przypadku, gdy którakolwiek A lub B przyczyny skutki uboczne lub skomplikowanych obliczeń.

Możliwe wyjątek dla obu jest taki sam, jeśli masz niestandardową definicję operator!, w którym to przypadku nie są one w rzeczywistości równoważne.

+0

zakładając, że A i B są jednocześnie 'bool', wtedy nie ma żadnej różnicy funkcjonalnej ? – Matthew

+0

@Matthew: Zakładając, że "A" i "B" są zmiennymi lokalnymi typu 'bool', nie powinno być żadnych różnic w generowanym kodzie. –

+0

Myślałem, że to zależy od prawdopodobieństwa, że ​​A będzie "prawdziwe", ale mówisz mi, że kompilują się do identycznego kodu? Ciekawy. – Matthew

-1

Mój krótki test 10000 porównań między tymi dwoma mówi, że firsoneis jest szybszy.

mówi, że pierwsza potrzebowała całkowicie 1353 kleszczy, a druga w sumie 1373 kleszczy.

EDYCJA: potem znowu próbowałem to kilka razy wcześniej, a wyniki zmieniają się, więc obie są takie same.

Powiązane problemy