Wyjaśnij ten fragment, który znajduje maksymalnie dwie liczby całkowite bez użycia if-else lub jakiegokolwiek innego operatora porównania?
Znajdź maksymalnie dwie liczby. Nie należy używać if-else ani żadnego innego operatora porównującego. Znalazłem to pytanie na internetowej tablicy ogłoszeń, więc pomyślałem, że powinienem zapytać w StackOverflow
Przykład Wejść: 5, 10 Wyjście: 10
Znalazłem takie rozwiązanie, czy ktoś może mi pomóc zrozumieć te linie kodu
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
19 answers
int getMax(int a, int b) {
int c = a - b;
int k = (c >> 31) & 0x1;
int max = a - k * c;
return max;
}
Zbadajmy to. Ta pierwsza linia wydaje się być prosta - przechowuje różnicę a
i b
. Wartość ta jest ujemna, jeśli a < b
i jest niejednoznaczna w przeciwnym razie. Rzeczywiście jest tu błąd - jeśli różnica liczb a
i b
jest tak duża, że nie może zmieścić się w liczbie całkowitej, doprowadzi to do niezdefiniowanego zachowania - oops! Załóżmy, że to się tu nie dzieje.
W następnym wierszu, czyli
int k = (c >> 31) & 0x1;
Chodzi o to, aby sprawdzić, czy wartość c
jest ujemna. W praktycznie wszystkich nowoczesnych komputerach, liczby są przechowywane w formacie zwanym dopełnieniem dwójki , w którym najwyższym bitem liczby jest 0, jeśli liczba jest dodatnia, a 1, jeśli liczba jest ujemna. Co więcej, większość ints to 32 bity. (c >> 31)
przesuwa liczbę w dół o 31 bitów, pozostawiając najwyższy bit liczby w miejscu dla najniższego bitu. Następnym krokiem jest wzięcie tej liczby i dodanie jej z 1 (którego binarna reprezentacja jest 0 wszędzie z wyjątkiem ostatni bit) usuwa wszystkie wyższe bity i po prostu daje najniższy bit. Ponieważ najniższy bit c >> 31
jest najwyższym bitem c
, odczytuje się najwyższy bit c
jako 0 LUB 1. Ponieważ najwyższy bit to 1 iff c
to 1, jest to sposób sprawdzania, czy c
jest ujemne (1) Czy dodatnie (0). Łącząc to rozumowanie z powyższym, k
jest 1 Jeśli a < b
i jest 0 w przeciwnym razie.
Ostatnim krokiem jest zrobienie tego:
int max = a - k * c;
If a < b
, then k == 1
and k * c = c = a - b
, and więc
a - k * c = a - (a - b) = a - a + b = b
Który jest prawidłowym Maxem, ponieważ a < b
. W przeciwnym razie, jeśli a >= b
, to k == 0
i
a - k * c = a - 0 = a
Który jest również prawidłowym max.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-18 00:44:12
Zaczynamy: (a + b) / 2 + |a - b| / 2
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-23 07:41:47
Użyj bitowych hacków
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
Jeśli wiesz, że INT_MIN <= x - y <= INT_MAX,
to możesz użyć poniższego, co jest szybsze, ponieważ (x - y)
musi być ocenione tylko raz.
r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-30 18:39:14
(sqrt( a*a + b*b - 2*a*b ) + a + b) / 2
Jest to oparte na tej samej technice co mike.rozwiązanie dld , ale mniej "oczywiste" jest tutaj to, co robię. Operacja " abs " wygląda na to, że porównujesz znak czegoś, ale ja tutaj korzystam z faktu, że sqrt() zawsze zwróci ci dodatni pierwiastek kwadratowy, więc wyrównuję (a-b) wypisując go w całości, a następnie kwadrat-zakorzenienie go ponownie, dodając a+b i dzieląc przez 2.
Zobaczysz, że zawsze działa: np. przykład użytkownika 10 i 5 otrzymasz sqrt(100 + 25 - 100) = 5 Następnie dodać 10 i 5 daje 20 i podzielić przez 2 daje 10.
Jeśli użyjemy 9 i 11 jako liczby otrzymamy (sqrt(121 + 81 - 198) + 11 + 9)/2 = (sqrt(4) + 20) / 2 = 22/2 = 11
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:23
Najprostsza odpowiedź znajduje się poniżej.
#include <math.h>
int Max(int x, int y)
{
return (float)(x + y) / 2.0 + abs((float)(x - y) / 2);
}
int Min(int x, int y)
{
return (float)(x + y) / 2.0 - abs((float)(x - y) / 2);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-03 03:41:17
int max(int i, int j) {
int m = ((i-j) >> 31);
return (m & j) + ((~m) & i);
}
Rozwiązanie to pozwala uniknąć mnożenia. m będzie albo 0x00000000 albo 0xFFFFFFFF
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-10 19:09:14
Używając idei przesunięcia, aby wyodrębnić znak zamieszczony przez innych, oto inny sposób:
max (a, b) = new[] { a, b } [((a - b) >> 31) & 1]
To wypycha dwie liczby do tablicy z maksymalną liczbą określoną przez element tablicy, którego indeks jest bitem znaku różnicy między dwiema liczbami.
Zauważ, że:
- różnica
(a - b
) może się przepełnić. - Jeśli liczby są niepodpisane, a operator
>>
odnosi się do logicznego przesunięcia w prawo,& 1
jest zbędny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-23 08:19:13
Myślę, że zrobię to tak. Nie jest tak czytelny, jak byś chciał, ale kiedy zaczniesz od "jak zrobić X bez używania oczywistego sposobu robienia X, musisz się tego spodziewać. Teoretycznie rezygnuje to również z przenośności, ale musiałbyś znaleźć dość nietypowy system, aby zobaczyć problem.
#define BITS (CHAR_BIT * sizeof(int) - 1)
int findmax(int a, int b) {
int rets[] = {a, b};
return rets[unsigned(a-b)>>BITS];
}
To ma pewne zalety w stosunku do tego pokazanego w pytaniu. Po pierwsze, oblicza prawidłowy rozmiar przesunięcia, zamiast być kodowane na twardo dla 32-bitowych int. Po drugie, w przypadku większości kompilatorów możemy oczekiwać, że mnożenie nastąpi w czasie kompilacji, więc wszystko, co pozostało w czasie uruchamiania, to trywialna manipulacja bitami (odjęcie i przesunięcie), a następnie obciążenie i powrót. Krótko mówiąc, jest to prawie pewne, że jest to dość szybkie, nawet na najmniejszym mikrokontrolerze, gdzie oryginalne użyte mnożenie musiało się zdarzyć w czasie uruchamiania, więc chociaż prawdopodobnie jest to dość szybkie na komputerze stacjonarnym, często będzie nieco wolniejsze na małym mikrokontrolerze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-20 23:12:49
Oto co robią te linie:
C jest a-b. Jeśli C jest ujemne, a K jest 32. bitem c, który jest bitem znakowym c (zakładając 32-bitowe liczby całkowite. Jeśli jest to zrobione na platformie z 64-bitowymi liczbami całkowitymi, ten kod nie będzie działał). Przesuwa się 31 bitów w prawo, aby usunąć 31 bitów w prawo, pozostawiając bit znaku w najbardziej prawym miejscu, a następnie dodając 1, Aby usunąć wszystkie bity w lewo (które zostaną wypełnione 1s, jeśli c jest ujemne). Więc k będzie równa 1, Jeśli C jest ujemne i 0, Jeśli c jest dodatnie. Wtedy max = A - k * c. Jeśli c jest 0, oznacza to a>=b, więc max jest a - 0 * c = a. jeśli c jest 1, oznacza to, że A
Ogólnie rzecz biorąc, to tylko użycie bitu znaku różnicy, aby uniknąć użycia operacji większych lub mniejszych niż. Szczerze mówiąc, trochę głupio jest powiedzieć, że ten kod nie używa porównania. c jest wynikiem porównania a I B. kod po prostu nie używa operatora porównania. Mógłbyś zrób podobnie w wielu kodach asemblacji, po prostu odejmując liczby, a następnie przeskakując na podstawie wartości ustawionych w rejestrze stanu. Dodam jeszcze, że wszystkie te rozwiązania zakładają, że obie liczby są liczbami całkowitymi. Jeśli są to pływaki, dublerzy lub coś bardziej skomplikowanego (Biginty, Liczby wymierne itp.) wtedy naprawdę trzeba użyć operatora porównania. Bit-triki na ogół nie robią dla nich.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-23 09:01:19
Funkcja GetMax() Bez Operacji Logicznych -
int getMax(int a, int b){
return (a+b+((a-b)>>sizeof(int)*8-1|1)*(a-b))/2;
}
Wyjaśnienie:
Rozbijmy 'max' na kawałki,
max
= ( max + max ) / 2
= ( max + (min+differenceOfMaxMin) ) / 2
= ( max + min + differenceOfMaxMin ) / 2
= ( max + min + | max - min | ) ) / 2
Więc funkcja powinna wyglądać tak-
getMax(a, b)
= ( a + b + absolute(a - b) ) / 2
Teraz,
absolute(x)
= x [if 'x' is positive] or -x [if 'x' is negative]
= x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
W liczbie całkowitej dodatniej pierwszy bit (bit znaku) jest- 0; w negatywie jest- 1. Przesuwając bity w prawo ( > > ) można przechwycić pierwszy bit.
Podczas przesunięcia w prawo pustą przestrzeń wypełnia znak trochę. Więc 01110001 >> 2 = 00011100, while 10110001 >> 2 = 11101100.
W rezultacie dla 8-bitowego przesunięcia liczb 7-bitowych albo wytworzy- 1 1 1 1 1 1 1 [0 LUB 1] dla ujemnych, lub 0 0 0 0 0 0 0 [0 LUB 1] dla dodatnich.
Teraz, jeśli lub operacja jest wykonywana z 00000001 (= 1), liczba ujemna- 11111111 (= -1), i dodatni - 00000001 (= 1).
Więc,
absolute(x)
= x * ( 1 [if 'x' is positive] or -1 [if 'x' is negative] )
= x * ( ( x >> (numberOfBitsInInteger-1) ) | 1 )
= x * ( ( x >> ((numberOfBytesInInteger*bitsInOneByte) - 1) ) | 1 )
= x * ( ( x >> ((sizeOf(int)*8) - 1) ) | 1 )
Wreszcie,
getMax(a, b)
= ( a + b + absolute(a - b) ) / 2
= ( a + b + ((a-b) * ( ( (a-b) >> ((sizeOf(int)*8) - 1) ) | 1 )) ) / 2
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-31 03:15:22
Static int mymax (int a, int b)
{
int[] arr;
arr = new int[3];
arr[0] = b;
arr[1] = a;
arr[2] = a;
return arr[Math.Sign(a - b) + 1];
}
Jeśli b > A then (a-b) będzie ujemne, znak zwróci -1, dodając 1 otrzymamy indeks 0, który jest b, jeśli b=a to a-b będzie 0, +1 Da indeks 1, więc nie ma znaczenia, czy zwracamy a czy b, gdy A > B to a-b będzie dodatnie, a znak zwróci 1, dodając 1 otrzymamy indeks 2, Gdzie a jest przechowywane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-25 13:23:17
#include<stdio.h>
main()
{
int num1,num2,diff;
printf("Enter number 1 : ");
scanf("%d",&num1);
printf("Enter number 2 : ");
scanf("%d",&num2);
diff=num1-num2;
num1=abs(diff);
num2=num1+diff;
if(num1==num2)
printf("Both number are equal\n");
else if(num2==0)
printf("Num2 > Num1\n");
else
printf("Num1 > Num2\n");
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-26 10:25:54
Kod, który podaję, służy do znalezienia maksymalnie dwóch liczb, liczby mogą być dowolnego typu danych(integer, floating). Jeżeli liczby wejściowe są równe, to funkcja zwraca liczbę.
double findmax(double a, double b)
{
//find the difference of the two numbers
double diff=a-b;
double temp_diff=diff;
int int_diff=temp_diff;
/*
For the floating point numbers the difference contains decimal
values (for example 0.0009, 2.63 etc.) if the left side of '.' contains 0 then we need
to get a non-zero number on the left side of '.'
*/
while ( (!(int_diff|0)) && ((temp_diff-int_diff)||(0.0)) )
{
temp_diff = temp_diff * 10;
int_diff = temp_diff;
}
/*
shift the sign bit of variable 'int_diff' to the LSB position and find if it is
1(difference is -ve) or 0(difference is +ve) , then multiply it with the difference of
the two numbers (variable 'diff') then subtract it with the variable a.
*/
return a- (diff * ( int_diff >> (sizeof(int) * 8 - 1 ) & 1 ));
}
Opis
- pierwszą rzeczą, jaką funkcja pobiera argumenty jako podwójne i ma typ return jako podwójne. Powodem tego jest stworzenie jednej funkcji, która może znaleźć maksimum dla wszystkich typów. Gdy podane są liczby typu integer lub jeden jest liczba całkowita i inne jest zmiennoprzecinkowa wtedy również ze względu na konwersję implicit funkcja może być używana do znalezienia max dla liczb całkowitych również.
- podstawowa logika jest prosta, Załóżmy, że mamy dwie liczby a & b Jeśli A-b>0(tzn. różnica jest dodatnia) to a jest maksimum else jeśli A-b==0 to obie są równe i jeśli A-B
-
Bit znaku jest zapisywany jako najbardziej znaczący Bit (MSB) w pamięci. Jeśli MSB jest 1 i odwrotnie. Aby sprawdzić czy MSB jest 1 Czy 0 przesuwamy MSB do pozycji LSB i bitowo & z 1, jeśli wynikiem jest 1, to liczba jest -ve else no. is + ve. Wynik ten otrzymuje się za pomocą twierdzenia:
Int_diff > >(sizeof(int) * 8 - 1 ) & 1
Tutaj aby uzyskać bit znaku z MSB do LSB przenosimy go na bity k-1 (gdzie k jest liczbą bitów potrzebnych do zapisania liczby całkowitej w pamięci, która zależy od typu systemu). Tutaj k = sizeof(int) * 8 as sizeof() podaje liczbę bajtów potrzebnych do zapisania liczba całkowita, aby uzyskać nie. bitów mnożymy przez 8. Po prawej przesunięciu, stosujemy bitowe & z 1, Aby uzyskać wynik.
-
Teraz po uzyskaniu wyniku(Załóżmy go jako r) jako 1 (dla-ve różnicy) i 0 (dla +ve różnicy) pomnożymy wynik przez różnicę dwóch liczb, logika jest podana w następujący sposób:
- Jeśli a > b to a-b>0 tzn. jest + ve więc wynikiem jest 0 (tzn. r=0). Tak więc a-(A-b) * r => A-(A-b) * 0, co daje ' a ' jako maksimum.
- if a A-(A-b) * 1 = >a-A+b = > B , co daje " B " jako maksimum.
-
Teraz pozostały dwa punkty 1. zastosowanie pętli while oraz 2. dlaczego użyłem zmiennej 'int_diff' jako liczby całkowitej. Aby odpowiedzieć na te pytania, musimy zrozumieć kilka punktów:
- zmiennoprzecinkowe wartości typu nie mogą być używane jako operand dla operatorów bitowych.
- z powyższego powodu, musimy uzyskać wartość w wartość całkowita, aby uzyskać znak różnicy za pomocą operatorów bitowych. Te dwa punkty opisują potrzebę zmiennej "int_diff" jako typu integer.
- teraz powiedzmy, że znajdujemy różnicę w zmiennej 'diff' teraz istnieją 3 możliwości dla wartości 'diff' niezależnie od znaku tych wartości. a). / diff / > = 1, (b). 0
- kiedy przypisujemy podwójną wartość do zmiennej integer, część dziesiętna jest tracona.
- Dla case (a) wartość 'int_diff' >0 (tj. 1,2,...). Dla pozostałych dwóch przypadków int_diff=0.
- warunek (temp_diff-int_diff) / / 0.0 sprawdza, czy diff= = 0, więc obie liczby są równe.
- If diff!=0 wtedy sprawdzamy czy int_diff / 0 jest true tzn., case(b) jest true
- W pętli while staramy się uzyskać wartość int_diff jako niezerową, tak aby wartość int_diff otrzymała również znak diff.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-05 12:32:14
Oto kilka metod bit-twidling , aby uzyskać maksimum dwóch wartości całkowych:
Metoda 1
int max1(int a, int b) {
static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1;
int mask = (a - b) >> SIGN_BIT_SHIFT;
return (a & ~mask) | (b & mask);
}
Wyjaśnienie:
- (A - b) >> SIGN_BIT_SHIFT - Jeśli
a > b
toa - b
jest dodatnie, więc bit znaku to0
, A Maska to0x00.00
. W przeciwnym raziea < b
więc {[3] } jest ujemne, bit znaku jest1
i po przesunięciu otrzymujemy maskę0xFF..FF
- (a & ~mask) - jeśli maska jest
0xFF..FF
, to~mask
jest0x00..00
i wtedy ta wartość jest0
. W przeciwnym razie~mask
jest0xFF..FF
, a wartośća
- (B & mask) - jeśli maska wynosi
0xFF..FF
, to ta wartość tob
. W przeciwnym raziemask
jest0x00..00
, a wartość0
.
Wreszcie:
- jeśli
a >= b
toa - b
jest dodatnie, otrzymujemymax = a | 0 = a
- Jeśli
a < b
toa - b
jest ujemne, otrzymujemymax = 0 | b = b
Metoda 2
int max2(int a, int b) {
static const size_t SIGN_BIT_SHIFT = sizeof(a) * 8 - 1;
int mask = (a - b) >> SIGN_BIT_SHIFT;
return a ^ ((a ^ b) & mask);
}
Wyjaśnienie:
- Wyjaśnienie maski jest takie samo jak dla metody 1 . Jeśli
a > b
Maska to0x00..00
, inaczej Maska to0xFF..FF
- jeśli maska jest
0x00..00
, to(a ^ b) & mask
jest0x00..00
- jeśli maska jest
0xFF..FF
, to(a ^ b) & mask
jesta ^ b
Wreszcie:
- jeśli
a >= b
, otrzymujemya ^ 0x00..00 = a
- Jeśli
a < b
, otrzymujemya ^ a ^ b = b
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-08 22:39:53
Logika opisana w problemie może być wyjaśniona tak, jakby 1. liczba była mniejsza, to 0 zostanie odjęte, inaczej różnica zostanie odjęta od 1.Liczby, aby uzyskać 2. liczbę. Znalazłem jeszcze jedno rozwiązanie matematyczne, które moim zdaniem jest nieco prostsze do zrozumienia tej koncepcji.
Rozważając a i b jako podane liczby
c=|a/b|+1;
d=(c-1)/b;
smallest number= a - d*(a-b);
Ponownie chodzi o to, aby znaleźć k, które jest więdnące 0 LUB 1 i pomnożyć go przez różnicę dwóch liczb.I na koniec liczba ta powinna być odejmowana od 1. Liczba, aby uzyskać mniejszą z dwóch liczb. P. S. To rozwiązanie nie powiedzie się w przypadku, gdy 2nd number to zero
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-25 06:18:59
int a=151;
int b=121;
int k=Math.abs(a-b);
int j= a+b;
double k1=(double)(k);
double j1= (double) (j);
double c=Math.ceil(k1/2) + Math.floor(j1/2);
int c1= (int) (c);
System.out.println(" Max value = " + c1);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-10 18:52:50
(A / b) * b + (b / a) * a - (A/b)*(b/A)*a + (abs(a - b) % a) % b
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-24 20:39:01
Jest jeden sposób
public static int Min(int a, int b)
{
int dif = (int)(((uint)(a - b)) >> 31);
return a * dif + b * (1 - dif);
}
I jeden
return (a>=b)?b:a;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-01 11:22:30
Chyba możemy po prostu pomnożyć liczby za pomocą ich porównań bitowych np:
int max=(a>b)*a+(a<=b)*b;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-12 01:59:53