Dotyczy to wszystkich liczb ujemnych.
f (n) = abs (n)
Ponieważ istnieje jeszcze jedna liczba ujemna niż liczba dodatnia dla dwóch liczb całkowitych uzupełniających, f(n) = abs(n) jest ważna dla jednego przypadku więcej niż f(n) = n > 0 ? -n : nrozwiązanie, które jest takie samo jak f(n) = -abs(n). Mam cię po jednym ...: D
AKTUALIZACJA
Nie, nie dotyczy to więcej niż jednego przypadku, jak właśnie rozpoznałem w komentarzu litba ... abs(Int.Min) po prostu się przepełni ...
Myślałem też o użyciu informacji o modzie 2, ale doszedłem do wniosku, że to nie działa ... na początku. Jeśli zrobisz to poprawnie, zadziała dla wszystkich liczb opróczInt.Min tego, że się przepełni.
AKTUALIZACJA
Bawiłem się nim przez pewien czas, szukając ładnej sztuczki manipulacji, ale nie mogłem znaleźć ładnego jednoliniowego, podczas gdy rozwiązanie mod 2 pasuje do jednego.
f (n) = 2n (abs (n)% 2) - n + sgn (n)
W języku C # wygląda to następująco:
public static Int32 f(Int32 n)
{
return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
Aby to działa dla wszystkich wartości, trzeba wymienić Math.Abs()z (n > 0) ? +n : -nobejmują obliczenia w uncheckedbloku. Następnie zostajesz nawet Int.Minzmapowany do siebie, tak jak robi to niesprawdzona negacja.
AKTUALIZACJA
Zainspirowany inną odpowiedzią wyjaśnię, jak działa ta funkcja i jak ją zbudować.
Zacznijmy od samego początku. Funkcja fjest wielokrotnie stosowana do danej wartościn dając ciąg wartości.
n => f (n) => f (f (n)) => f (f (f (n))) => f (f (f (f (n)))) => ...
Pytanie wymaga f(f(n)) = -n, aby były to dwa kolejne zastosowania fnegacji argumentu. Dwa kolejne zastosowania f- w sumie cztery - negują ponownie ten argumentn ponownie.
n => f (n) => -n => f (f (f (n))) => n => f (n) => ...
Teraz jest oczywisty cykl długości czterech. Podstawiając x = f(n)i zauważając, że otrzymane równanie f(f(f(n))) = f(f(x)) = -xzachowuje, otrzymujemy następujące wyniki.
n => x => -n => -x => n => ...
Otrzymujemy więc cykl długości cztery z dwiema liczbami i dwie liczby zanegowane. Jeśli wyobrażasz sobie cykl jako prostokąt, zanegowane wartości znajdują się w przeciwległych rogach.
Jednym z wielu rozwiązań pozwalających skonstruować taki cykl jest początek od n.
n => neguj i odejmij jeden
-n - 1 = - (n + 1) => dodaj jeden
-n => zaneguj i dodaj jeden
n + 1 => odejmij jeden
n
Konkretnym przykładem takiego cyklu jest +1 => -2 => -1 => +2 => +1. Prawie skończyliśmy. Zwracając uwagę, że skonstruowany cykl zawiera nieparzystą liczbę dodatnią, jego parzysty następca i obie liczby negują, możemy z łatwością podzielić liczby całkowite na wiele takich cykli ( 2^32jest wielokrotnością czterech) i znaleźliśmy funkcję, która spełnia warunki.
Ale mamy problem ze zerem. Cykl musi zawierać, 0 => x => 0ponieważ zero jest negowane samo w sobie. A ponieważ cykl stwierdza, 0 => xże już następuje 0 => x => 0 => x. Jest to tylko cykl długości dwóch i xzamienia się w siebie po dwóch aplikacjach, a nie w -x. Na szczęście jest jeden przypadek, który rozwiązuje problem. Jeśli Xjest równy zeru, otrzymujemy cykl długości zawierający tylko zero i rozwiązaliśmy ten problem, stwierdzając, że zero jest stałym punktem f.
Gotowy? Prawie. Mamy 2^32liczby, zero to stały punkt pozostawiający 2^32 - 1liczby i musimy podzielić tę liczbę na cykle czterech liczb. Złe, że 2^32 - 1nie jest wielokrotnością czterech - pozostaną trzy liczby nie w żadnym cyklu długości czterech.
Wyjaśnię pozostałą część rozwiązania przy użyciu mniejszego zestawu 3-bitowych liczb całkowitych ze znakiem od -4do +3. Skończyliśmy z zerem. Mamy jeden pełny cykl +1 => -2 => -1 => +2 => +1. Teraz skonstruujmy cykl zaczynając od +3.
+3 => -4 => -3 => +4 => +3
Powstaje problem polegający na tym, że +4nie jest reprezentowana jako 3-bitowa liczba całkowita. Chcielibyśmy uzyskać +4poprzez zanegowanie -3się +3- co jest jeszcze ważne całkowitą 3 bit - ale potem dodając jeden do +3(binarnie 011) daje 100binarny. Jest interpretowany jako liczba całkowita bez znaku, +4ale musimy interpretować go jako liczbę całkowitą ze znakiem -4. Tak więc w rzeczywistości -4w tym przykładzie lub Int.MinValuew ogólnym przypadku jest drugim stałym punktem całkowitej negacji arytmetycznej - 0 i Int.MinValuesą one odwzorowane na nich samych. Tak więc cykl jest następujący.
+3 => -4 => -3 => -4 => -3
Jest to cykl długości dwóch i dodatkowo +3wchodzi w cykl poprzez -4. W konsekwencji -4jest poprawnie odwzorowany na siebie po dwóch aplikacjach funkcyjnych, +3jest poprawnie odwzorowany na -3dwóch aplikacjach funkcyjnych, ale -3błędnie jest odwzorowany na sobie po dwóch aplikacjach funkcyjnych.
Stworzyliśmy więc funkcję, która działa dla wszystkich liczb całkowitych oprócz jednej. Czy możemy zrobić lepiej? Nie, nie możemy. Dlaczego? Musimy skonstruować cykle o długości czterech i jesteśmy w stanie objąć cały zakres liczb całkowitych do czterech wartości. Pozostałe wartości są dwa punkty stałe 0i Int.MinValuektóre muszą być przypisane do siebie i dwóch dowolnych liczb całkowitych xi -xktóre muszą być przypisane do siebie przez dwa wnioski funkcyjnych.
Mapować xdo -xi odwrotnie muszą tworzyć cztery cyklu i muszą być umieszczone na przeciwległych rogach tego cyklu. W konsekwencji 0i Int.MinValuemuszą znajdować się również w przeciwległych rogach. To będzie poprawnie map xi -xjednak zamienić dwa punkty stałe 0i Int.MinValuepo dwóch zastosowaniach funkcyjnych i zostawić nas z dwoma wejściami upadających. Dlatego nie jest możliwe zbudowanie funkcji, która działa dla wszystkich wartości, ale mamy taką, która działa dla wszystkich wartości oprócz jednej i jest to najlepsze, co możemy osiągnąć.