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 : n
rozwią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 : -n
obejmują obliczenia w unchecked
bloku. Następnie zostajesz nawet Int.Min
zmapowany 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 f
jest 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 f
negacji 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)) = -x
zachowuje, 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^32
jest wielokrotnością czterech) i znaleźliśmy funkcję, która spełnia warunki.
Ale mamy problem ze zerem. Cykl musi zawierać, 0 => x => 0
ponieważ 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 x
zamienia się w siebie po dwóch aplikacjach, a nie w -x
. Na szczęście jest jeden przypadek, który rozwiązuje problem. Jeśli X
jest 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^32
liczby, zero to stały punkt pozostawiający 2^32 - 1
liczby i musimy podzielić tę liczbę na cykle czterech liczb. Złe, że 2^32 - 1
nie 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 -4
do +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 +4
nie jest reprezentowana jako 3-bitowa liczba całkowita. Chcielibyśmy uzyskać +4
poprzez zanegowanie -3
się +3
- co jest jeszcze ważne całkowitą 3 bit - ale potem dodając jeden do +3
(binarnie 011
) daje 100
binarny. Jest interpretowany jako liczba całkowita bez znaku, +4
ale musimy interpretować go jako liczbę całkowitą ze znakiem -4
. Tak więc w rzeczywistości -4
w tym przykładzie lub Int.MinValue
w ogólnym przypadku jest drugim stałym punktem całkowitej negacji arytmetycznej - 0
i Int.MinValue
są 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 +3
wchodzi w cykl poprzez -4
. W konsekwencji -4
jest poprawnie odwzorowany na siebie po dwóch aplikacjach funkcyjnych, +3
jest poprawnie odwzorowany na -3
dwóch aplikacjach funkcyjnych, ale -3
błę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 0
i Int.MinValue
które muszą być przypisane do siebie i dwóch dowolnych liczb całkowitych x
i -x
które muszą być przypisane do siebie przez dwa wnioski funkcyjnych.
Mapować x
do -x
i odwrotnie muszą tworzyć cztery cyklu i muszą być umieszczone na przeciwległych rogach tego cyklu. W konsekwencji 0
i Int.MinValue
muszą znajdować się również w przeciwległych rogach. To będzie poprawnie map x
i -x
jednak zamienić dwa punkty stałe 0
i Int.MinValue
po 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ąć.