2016-10-29 32 views
5

natknąłem się na ten kod:Jak działa ta funkcja min()?

int __min(int a, int b) { 
    return ((a)-(((a)-(b))&((b)-(a))>>31)); 
} 

mogę sobie wyobrazić, że to ma coś wspólnego z 2s uzupełnienie, i że to działa tylko dla 32-bitowych liczb całkowitych podpisane, ale po tym gubię.

Znalazłem this question, ale nie sądzę, że funkcje są ze sobą powiązane, czy też się mylę?

Więc mam 2 pytania:

  1. Dlaczego to działa funkcja?
  2. Czy istnieje sytuacja, w której (a<b)?a:b nie działałaby i ta funkcja byłaby, lub czy ta funkcja jest zbyt skomplikowana dla zabawy?

EDIT: Funkcja jest napisany dla GPU, więc myślę @Banex może mieć rację o celu pisania, podobnie jak to jest w celu uniknięcia rozgałęzienia.

+5

Nie mogę zagwarantować poprawności, ale mogę sobie wyobrazić, że głównym celem tej funkcji jest unikanie rozgałęzień. – Banex

+1

@Banex Funkcja została napisana dla gpu, myślę, że to miałoby sens, dobry punkt! –

+1

Opiera się również na zawijanym arytmetycznym przepełnieniu w aritmetyce wokół –

Odpowiedz

2

Został zaprojektowany do pracy z 32-bitowymi wartościami podpisanymi. Zróbmy to krok po kroku.

((b)-(a))>>31) 

Prawy operator przesunięcia w zasadzie przyjmuje najwyższy bit w wartości 32-bitowej, a znak-rozszerza go do pozostałych 31 bitów. Tak działa operator prawej zmiany dla wartości podpisanych.

Jeśli b jest większa niż a, wynik odejmowania będzie dodatni, najwyższy bit będzie 0, a rezultatem tego jest 0.

Jeśli b jest mniejsza niż a, wynik z odejmowanie będzie ujemne, najwyższy bit będzie wynosił 1, a wynikiem będzie -1. Najwyższy bit zostanie przesunięty w dół do wszystkich pozostałych bitów. Wszystkie bity w 32-bitowej wartości zostaną ustawione, co oznacza -1.

Możesz to sprawdzić samodzielnie, pisząc krótki program, który umieszcza wartość dodatnią lub ujemną w 32-bitowym int, przesuwa w prawo o 31-bitów; następnie obserwując, że wynik będzie wynosił 0 lub -1. Jak wiadomo, w arytmetyce uzupełnień dwubajtowych wartość -1 zawiera wszystkie ustawione bity.

((a)-(b)) & (0 or -1, as the result of the previous operation). 

Tak więc, jeśli b jest mniejsza niż a, prawa ręka ma wartość bok wszystkie bity ustawione, a wynik z operatorem bitowym & jest wartość po lewej stronie. lub a-b.

Jeśli b jest większa niż a, wartość po prawej stronie ma wszystkie bity 0, a wynikiem & jest 0.

Podsumowując:

If b jest mniejsza niż a, powyższe wyrażenie do:

a-(a-b) 

or 

a-a+b 

or 

b 

A jeśli b jest większa niż a, wynikiem wyrażenia jest

a - 0 

or 

a 
0

Wyrażenie

((a)-(b))&((b)-(a))>>31 

czyli bez najbardziej zbędny nawiasie

(a - b) & (b - a) >> 31 

ocenia się

a - b 

jeśli a> b oraz

0 

inaczej, więc jeśli to jest w końcu odejmowana od A jest taki sam jak

if (a > b) 
    return (a - (a - b)); 
else 
    return (a - 0);