2012-07-18 16 views
5

Obecnie dokonuję konwersji niektórych kodu OpenCV z C++ na Javę. Nie mogę używać JavaCV, ponieważ potrzebujemy konwersji w natywnej Javie, a nie w JNA. W pewnym momencie w kodzie, otrzymuję następujące zadania:W jaki sposób operator Unarius minus działa na wartości logiczne w C++?

dst[x] = (uchar)(-(kHit >= kForeground)); 

Gdzie dst jest uchar*, kHit i kForegroundint s.

Nie udało mi się znaleźć niczego na temat tego, jak to działa, a Java nie rozpozna go jako operacji. Operacja na tych dwóch zmiennych odbywa się w innym punkcie kodu i przechowuje jedną z dwóch wartości: 255 lub 0.

Ten kod pochodzi z opencv/video/src/bgfg_gaussmix.cpp.

Odpowiedz

7

W języku C++ wyrażenie binarne generuje jedną z dwóch wartości - 0 lub 1. Gdy zastosujesz jednolity minus - do wyniku, otrzymasz 0 lub -1. Kiedy ponownie interpretujesz -1 jako uchar, otrzymujesz 255.

można przekonwertować to wyrażenie Java z warunkowym:

dst[x] = (kHit >= kForeground) ? 255 : 0; 

Ponieważ rozgałęzienia, to nie będzie tak szybko, jak oryginalne. Niewiele można jednak zrobić, jeśli chodzi o szybkość, ponieważ Java nie ma umiejętności ponownego interpretowania wartości logicznych jako liczb.

+0

Ma to sens i jest czymś, co mogłem bardzo łatwo przetestować i odkryć na własną rękę. Dziękuję za zwrócenie uwagi na tak zwięzłe. – Wraith967

+0

Technicznie wyrażenie boolowskie daje "true" lub "false', które po awansie do' int' otrzymają wartości "1" lub "0". –

6

kHit >= kForeground powraca albo true lub false, co w C++ oznacza 1 lub 0 rodzaju. Wartość ujemna z przodu przekształca to w -1 lub 0. Obsada do uchar ((uchar)) zwraca 0 dla 0 i opakowuje do 255 dla negatywu -1.

Po komentarzu Konrada, jestem również sceptyczny, to jest dobrze zdefiniowane. Jest dobrze zdefiniowany, ale wciąż jest okropnym kawałkiem kodu pod względem czytelności. :)

+3

Włącz * niektóre * kompilator/urządzenie. Ten kod jest niepotrzebnie nieprzenośny. –

+2

Czy standard C++ nie określa jawnie typów bez znaku, które zachowują się tak, jakby były dwójkami-dopełniaczami, więc powinno to być dobrze zdefiniowane (jako prawda = = 1 i fałsz == 0 jest również dobrze zdefiniowany)? –

+0

@KonradRudolph: Standard określa, że ​​'Wartość domyślna bool może zostać przekonwertowana na wartość typu int, przy czym false staje się zerem, a true staje się jednym. [Conv.prom], i że' Jeśli typ miejsca docelowego jest niepodpisany, wynikowa wartość jest najmniej nieakceptowaną liczbą całkowitą odpowiadającą źródłowej liczbie całkowitej (modulo 2n, gdzie n jest liczbą bitów używanych do reprezentowania typu bez znaku) '[conv.integral]. Więc myślę, że ten kod jest właściwie dobrze zdefiniowany i przenośny w kompilatorach. –

1

Co to w zasadzie nie jest następujący:

kHit >= kForeground 

jest wyrazem typu bool

-(kHit >= kForeground) 

konwertuje bool do int (w oparciu o true==1 i false==0) i neguje go, co powoduje w true==-1 i false==0.

To jest następnie konwertowane na uchar, co daje -1==255 i 0==0.

Należy zauważyć, że chociaż wydaje się, że wykorzystują one podstawowe szczegóły implementacji liczb, wszystkie te konwersje są gwarantowane przez standardy C++ i C, ponieważ ujemne liczby bez znaku są określone, aby zachowywać się zgodnie z dwójką-dopełnieniem.

Ale jeśli Java nie obsługuje tej funkcji, zawsze można zastąpić go przez przypisanie warunkowego:

dst[x] = (kHit>=kForeground) ? 255 : 0; 
1

Wyrażenie (kHit >= kForeground) daje wartość logiczną, która ma wartość true lub false. Gdy jednoskładnikowa - jest stosowany, bool awansuje do int, a konwersja daje 1 dla true lub 0 dla false. Po promocji znak zmienia się na -1 lub 0, a następnie przekształca się w uchar przez zewnętrzny odlew.

Należy zauważyć, że ważną informacją jest to, że jednoargumentowa operator- nie została zastosowana do wartości logicznej, ale wartość boolowska jest przekształcana na int, a następnie jest stosowana. Które mogą być testowane z odrobiną magii szablonu:

template <typename T, typename U> 
struct same_type { 
    static const bool value = false; 
}; 
template <typename T> 
struct same_type<T,T> { 
    static const bool value = true; 
}; 
template <typename T> 
void f(T value) { 
    std::cout << "Is int? " << std::boolalpha << same_type<T, int>::value << "\n"; 
    std::cout << "Is bool? " << same_type<T, bool>::value << "\n"; 
} 
int main() { 
    f(-true); 
} 

Szablon f testuje typ przekazany argument przeciwko int i bool za pomocą same_type szablony powyżej (dość trywialne do zrozumienia). Jeśli wywołujemy szablon f z -true jako odliczenie typu argumentu, ustawimy T na typ wyrażenia -true. Jeśli uruchomisz program, zobaczysz, że drukuje on Is int? true\nIs bool? false.

+0

Dobra odpowiedź, ale myślę, że można by zilustrować ilustrację konwersji całkowej z dwoma podstawowymi przeciążeniami. 'void f (int) {cout <<" int \ n "; } void f (bool) {cout << "bool \ n"; } f (true); f (-true); ' –

+0

@LucTouraille: Chyba po prostu miałem ten młotek (http://en.wikipedia.org/wiki/Law_of_the_instrument) w mojej skrzynce narzędziowej (teraz, gdy o tym myślę, jest prostsze podejście: 'szablon void print_type (T); print_type (-true);' ("print_type" zadeklarowany, nie zdefiniowany) powie ci typ w wiadomości linkera –