Ankieter niedawno zadał mi to pytanie: biorąc pod uwagę trzy zmienne logiczne, a, b i c, zwróć true, jeśli co najmniej dwie z trzech są prawdziwe.
Moje rozwiązanie jest następujące:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if ((a && b) || (b && c) || (a && c)) {
return true;
}
else{
return false;
}
}
Powiedział, że można to jeszcze poprawić, ale jak?
java
boolean
boolean-logic
282886
źródło
źródło
atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)
Odpowiedzi:
Zamiast pisać:
Pisać:
Jeśli chodzi o samo wyrażenie, coś takiego:
lub to (w zależności od tego, co łatwiej zrozumieć):
Testuje
a
ib
dokładnie raz, ac
najwyżej raz.Bibliografia
źródło
return hasGoodAttendance ? (passedCoursework || passed Exam) : (passedCoursework && passedExam)
, dla mnie to wygląda dobrze.atLeastTwo(hasgoodAttendance, passedCoursework, passedExam)
. Pomysł „co najmniej 2 boole są prawdziwe” jest na tyle ogólny, że zasługuje na swoją własną funkcję.Tylko ze względu na użycie XOR do rozwiązania stosunkowo prostego problemu ...
źródło
Dlaczego nie wdrożyć tego dosłownie? :)
W C możesz po prostu pisać
a+b+c >= 2
(lub!!a+!!b+!!c >= 2
być bardzo bezpiecznym).W odpowiedzi na TofuBeer porównania „s Java kodu bajtowego, o to prosty test wydajności:
Spowoduje to wydrukowanie następujących informacji na moim komputerze (z systemem Ubuntu na Intel Core 2 + Sun Java 1.6.0_15-b03 z maszyną wirtualną serwera HotSpot Server (14.1-b02, tryb mieszany)):
Pierwsza i druga iteracja:
Późniejsze iteracje:
Zastanawiam się, co mogłaby zrobić maszyna wirtualna Java, która z czasem obniża wydajność w przypadku (a + b + c> = 2).
A oto co się stanie, jeśli uruchomię Java z
-client
przełącznikiem VM:Zagadka...
A jeśli uruchomię go w GNU Java Interpreter , robi się prawie 100 razy wolniej, ale wtedy
a&&b || b&&c || a&&c
wersja wygrywa.Wyniki Tofubeera z najnowszym kodem z systemem OS X:
Wyniki od Paula Waglanda z Mac Java 1.6.0_26-b03-383-11A511
źródło
a+b+c >= 2
: to nie działa z negatywami, prawda? Być może będziesz musiał to zrobić!!a
, nie jestem pewien.Tego rodzaju pytania można rozwiązać za pomocą mapy Karnaugh :
z którego wywnioskujesz, że potrzebujesz grupy dla pierwszego rzędu i dwóch grup dla pierwszej kolumny, uzyskując optymalne rozwiązanie dla wieloskładnikowych środków smarnych:
źródło
Celem powinna być czytelność. Ktoś, kto czyta kod, musi natychmiast zrozumieć twoje zamiary. Oto moje rozwiązanie.
źródło
Seq(true, true, false).map(if (_) 1 else 0).sum >= 2
Wyjaśnienie:
Jeśli
a==b
, to oba są prawdziwe lub oba są fałszywe. Jeśli oba są prawdziwe, znaleźliśmy nasze dwa prawdziwe booleany i możemy zwrócić wartość true (przez powróta
). Jeśli oba są fałszywe, nie mogą istnieć dwa prawdziwe booleany, nawet jeślic
jest to prawda, więc zwracamy fałsz (przez powróta
). To jest(a==b) ? a
część. Co: c
? Cóż, jeślia==b
jest fałszywe, to dokładnie jedna za
lubb
musi być prawdziwa, więc znaleźliśmy pierwszą prawdziwą wartość logiczną, a jedyną rzeczą, która się liczy,c
jest również prawda, więc wrócimyc
jako odpowiedź.źródło
a
ib
zgadzają się, mają większość głosów, więc idź z tym, co to jest, w przeciwnym razie nie zgadzają się, takc
samo decyduje głosowanie”Nie musisz używać zwarć operatorów.
return (a & b) | (b & c) | (c & a);
Wykonuje tę samą liczbę operacji logicznych co twoja wersja, jednak jest całkowicie bez rozgałęzień.
źródło
Oto testowane, ogólne podejście. Nie tak „wydajny” jak większość dotychczas oferowanych rozwiązań, ale przejrzysty, przetestowany, działający i uogólniony.
źródło
Podsumowując. Nazywa się to algebrą boolowską z jakiegoś powodu:
Jeśli spojrzysz na tabele prawdy, zobaczysz, że mnożenie ma wartość logiczną i po prostu dodawanie jest xor.
Odpowiedzieć na Twoje pytanie:
źródło
return ((a?1:0) + (b?1:0) + (c?1:0)) >= 2
.źródło
To naprawdę zależy od tego, co rozumiesz przez „ulepszony”:
Jaśniejsze?
Terser?
Bardziej ogólne?
Bardziej skalowalny?
Szybciej?
To, który zostanie „ulepszony”, zależy w dużej mierze od sytuacji.
źródło
Oto kolejna implementacja korzystająca z mapowania / zmniejszania. To dobrze skaluje się do miliardów wartości logicznych © w środowisku rozproszonym. Za pomocą MongoDB:
Tworzenie bazy danych
values
logów:Tworząc mapę, zmniejsz funkcje:
Edycja : Podoba mi się odpowiedź CurtainDog na temat zastosowania mapowania / zmniejszania do list ogólnych, więc oto funkcja mapy, która pobiera wywołanie zwrotne, które określa, czy wartość powinna zostać policzona, czy nie.
Uruchamianie mapy / zmniejszanie:
źródło
Biorąc odpowiedzi (jak dotąd) tutaj:
i uruchomienie ich przez dekompilator (javap -c X> results.txt):
Widzisz, że?: Te są nieco lepsze niż poprawiona wersja twojego oryginału. Ten, który jest najlepszy, to ten, który całkowicie unika rozgałęzień. Jest to dobre z punktu widzenia mniejszej liczby instrukcji (w większości przypadków) i lepsze w przypadku części procesora przewidujących rozgałęzienia, ponieważ błędne odgadnięcie w przewidywaniu gałęzi może spowodować zablokowanie procesora.
Powiedziałbym, że najbardziej skuteczny jest ten z cienia księżyca. Wykorzystuje średnio najmniej instrukcji i zmniejsza ryzyko utknięcia rurociągu w procesorze.
Aby być w 100% pewnym, musisz znaleźć koszt (w cyklach procesora) dla każdej instrukcji, która niestety nie jest łatwo dostępna (musisz spojrzeć na źródło hotspotu, a następnie specyfikacje dostawców procesora na ten czas pobierane dla każdej wygenerowanej instrukcji).
Zobacz zaktualizowaną odpowiedź Rotsora, aby uzyskać analizę kodu wykonawczego.
źródło
Kolejny przykład kodu bezpośredniego:
Oczywiście nie jest to najbardziej zwięzły kod.
Uzupełnienie
Kolejna (nieco zoptymalizowana) wersja tego:
Może to działać nieco szybciej, przy założeniu, że porównanie z 0 spowoduje użycie szybszego (lub być może mniejszego) kodu niż porównanie z 2.
źródło
++n
jest szybsza niżn++
dlatego, że musisz wykonać kolejną kopię przed wykonaniem przyrostu .n
wyżej) każdy przyzwoity kompilator skompiluje każdą++
operację w jedną instrukcję CPU, zarówno przed, jak i po.Jeszcze inny sposób na zrobienie tego, ale niezbyt dobry:
Wartości
Boolean
hashcode są ustalone na 1231 dla wartości true i 1237 dla wartości false, więc równie dobrze mogłyby zostać użyte<= 3699
źródło
Najbardziej oczywistym zestawem ulepszeń są:
i wtedy
Ale te ulepszenia są niewielkie.
źródło
Nie lubię trójki (
return a ? (b || c) : (b && c);
z najwyższej odpowiedzi) i nie sądzę, żeby ktoś o tym wspominał. Jest napisane w ten sposób:źródło
W Clojure :
Stosowanie:
źródło
Nie sądzę, że widziałem jeszcze takie rozwiązanie:
Jego zaletą jest to, że gdy osiągnie liczbę, której szukasz, pęka. Więc jeśli było to „co najmniej 2 z tych 1 000 000 wartości są prawdziwe”, gdzie dwie pierwsze są rzeczywiście prawdziwe, to powinno pójść szybciej niż niektóre z bardziej „normalnych” rozwiązań.
źródło
boolean ... boolValues
, że łatwiej jest zadzwonić, ale nadal ma tablicęMożemy przekonwertować wartości logiczne na liczby całkowite i wykonać tę łatwą kontrolę:
źródło
Ponieważ nie określono, jak należy poprawić kod, postaram się ulepszyć kod, czyniąc go bardziej zabawnym. Oto moje rozwiązanie:
Jeśli ktoś zastanawia się, czy ten kod działa, oto uproszczenie z wykorzystaniem tej samej logiki:
}
Można to sprowadzić do następujących elementów:
Ale teraz to już nie jest śmieszne.
źródło
Zbyt wiele sposobów na zrobienie tego ...
źródło
Rozwiązanie AC
lub możesz preferować:
źródło
źródło
Najprostszy sposób (IMO), który nie jest mylący i łatwy do odczytania:
źródło
(C && (A || B)) || (A && B)
właśnie zmieniła * nazwy zmiennych ...Dosłowna interpretacja będzie działać we wszystkich głównych językach:
Ale prawdopodobnie ułatwiłbym ludziom czytanie i możliwość rozszerzenia na więcej niż trzy - coś, co wydaje się być zapomniane przez wielu programistów:
źródło
Jako dodatek do doskonałego postu @TofuBeer TofuBeer rozważ odpowiedź @pdox pdox:
Rozważ także jego zdemontowaną wersję podaną przez „javap -c”:
Odpowiedź pdox kompiluje się do mniej bajtowego kodu niż którakolwiek z poprzednich odpowiedzi. Jaki jest czas jego wykonania w porównaniu do innych?
Przynajmniej na moim komputerze odpowiedź pdox jest tylko nieco szybsza niż odpowiedź @moonshadow moonshadow, dzięki czemu pdox jest najszybszy ogólnie (na moim laptopie HP / Intel).
źródło
W Ruby:
[a, b, c].count { |x| x } >= 2
Które można uruchomić w JRuby na JavaVM. ;-)
źródło
Prawdopodobnie nie szuka czegoś zwiniętego, jak operatory porównania bitowego (zwykle nie jest to skomplikowane, ale w przypadku logicznych wartości, użycie operatorów bitowych jest niezwykle dziwne) lub czegoś, co jest bardzo okrągłe, jak konwersja na int i ich sumowanie.
Najbardziej bezpośrednim i naturalnym sposobem rozwiązania tego jest takie wyrażenie:
Jeśli wolisz, włącz tę funkcję, ale nie jest to zbyt skomplikowane. Rozwiązanie jest logicznie zwięzłe i wydajne.
źródło
W C:
źródło