Zamiana wartości zmiennych w c# - pytanie o rozwiązanie zadania

0

Kolejne zadanko z książki C# praktyczny kurs. Mam za zadanie zamienić warości zmiennych tak, aby zmienna a=b i b=a. Bez stosowania dodatkowych zmienych Poradziłem sobie z zastosowaniem dodatkowej zmiennej. W sieci znalazłem rozwiązanie zadania przez alternatywę wykluczającą – XOR.

a=a^b:
b=a^b;
a=a^b;

Autor pokrótce omawia XOR: „operacja XOR powoduje, że włączone zostają te bity, które miały różne stany w obu argumentach. Pozostałe bity zostają wyłączone. I tu pojawia się moje pytanie. Jak wpaść na to rozwiązanie. Wiem że dla doświadczonych programistów to banał, ale ja nie wiem czy po prostu nie czytam zbyt uważnie, czy jestem takim antytalentem informatycznym. Pozdrawiam Krzysztof :)

1

Exclusive or – zobacz na tabelę prawdy. Tak najszybciej załapiesz o co chodzi z xorowaniem bitów.

crispia napisał(a):

I tu pojawia się moje pytanie. Jak wpaść na to rozwiązanie.

Żeby móc dany problem rozwiązać konkretną operacją logiczną, trzeba wiedzieć jak one działają. W przeciwnym razie nawet nie przyjdzie to do głowy. Zaznaczyć jednak należy, że w typowym produkcyjnym kodzie nie stosuje się takich wyszukanych sztuczek, bo zmniejszają one czytelności kodu i utrudniają zrozumienie jego działania. Wyjątkiem są implementacje niskopoziomowe, tworzone z myślą o jak najwyższej efektywności.


Z drugiej strony, każdy programista powinien znać działanie wszystkich operacji logicznych, dostępnych w danym języku. To są absolutne podstawy, bez których praktycznie się nie obejdzie. To zadanko które rozwiązujesz, jest co najwyżej ciekawostką, więc nie przejmuj się, że sam nie wpadłeś na takie rozwiązanie.

Załóżmy, że masz dwie zmienne zawierające wartość logiczną – dla przykładu foo i bar. Do zmiennej result musisz wpisać true, ale tylko wtedy, gdy jedna zmienna zawiera truefoo albo bar. W przeciwnym razie trzeba wpisać false.

Można to zrealizować za pomocą instrukcji warunkowej:

if(foo)           // foo zawiera true
  result = !bar;  // bar musi zawierać false
else              // foo zawiera false
  result = bar;   // bar musi zawierać true

Można też skorzystać z xorowania, w celu pozbycia się warunku:

result = foo ^ bar;

Powyższe jest zwizualizowaniem tabeli prawdy:

result  foo  bar
0       0    0
1       0    1
1       1    0
0       1    1
2
a=a+b
b=a-b
a=a-b 
1
crispia napisał(a):

I tu pojawia się moje pytanie. Jak wpaść na to rozwiązanie.

Im większa wiedza i doświadczenie, tym łatwiej wpaść na rozwiązanie tego typu problemów. Jest w tym dużo losowości, bo zdarzają się sytuacje, gdy rozwiązanie przychodzi łatwo, i zdarzają się sytuacje, gdy nie można znaleźć rozwiązania mimo długiego zastanawiania się nad nim, a też czasami rozwiązanie nagle przychodzi w nieoczekiwanym momencie. Z tym jest tak samo, jak z rozwiązywaniem zagadek. Dobrze jest znać wzorce, które umożliwiają rozwiązywanie problemów bez konieczności wymyślania czegoś od nowa. W programowaniu takich wzorców jest dużo.

Można też wymyślić algorytm na sprawdzenie wszystkich możliwości. Na takiej samej zasadzie działają algorytmy znajdujące najkorzystniejszy ruch w grach, najkrótszą drogę, sekwencję o najmniejszej ilości kroków. Można utworzyć drzewo ze wszystkimi możliwościami i przeszukać je w głąb w celu znalezienia tych pasujących możliwości. Np. jeśli chcesz znaleźć takie rozwiązanie dla operacji + i - i dla uproszczenia zakładasz, że wystarczą trzy kroki, żeby osiągnąć cel, to drzewo wyglądałoby tak, że każdy element nadrzędny posiada cztery elementy podrzędne:

  • a = a + b
  • a = a - b
  • b = a + b
  • b = a - b

Mój program znalazł takie rozwiązania dla + i -:

1) a = a + b, b = a - b, a = a - b
2) b = a - b, a = a - b, b = a + b

Podobne dla * i /:

1) a = a * b, b = a / b, a = a / b
2) b = a / b, a = a / b, b = a * b

Możliwe, że to działa tylko dla par operacji odwrotnych względem siebie. Xor jest odwrotny dla samego siebie. Jak będę miał więcej czasu, to zrobię to samo dla większej kombinacji operacji.

2

Nie to, że się czepiam. Jednak trzeba zauważyć, że metoda którą podał @Marcin.Miga może spowodować przekroczenie zakresu zmiennej w przypadku dodawania dużych liczb pod górną granicą użytego typu. Np. podczas użycia 32 bitowego int'a bez znaku (zakres 0 - +4 294 967 295) jak zechcemy zamienić 2 duże liczby np 2 987 889 110 oraz 3 123 456 789 dojdzie do przekroczenia zakresu podczas sumowania i to jest UB. W przypadku metody wykorzystującej xorowanie takiego niebezpieczeństwa nie będzie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1