Questo è vero per tutti i numeri negativi.
f (n) = abs (n)
Poiché esiste un numero più negativo di quanti siano i numeri positivi per i numeri interi a due complementi, f(n) = abs(n)
è valido per un caso in più rispetto alla f(n) = n > 0 ? -n : n
soluzione uguale a f(n) = -abs(n)
. Ti ho preso per uno ...: D
AGGIORNARE
No, non è valido per un altro caso in quanto ho appena riconosciuto dal commento di Litb ... traboccerà abs(Int.Min)
...
Ho pensato di usare anche le informazioni sulla mod 2, ma ho concluso che non funziona ... troppo presto. Se fatto bene, funzionerà per tutti i numeri tranne Int.Min
perché questo traboccerà.
AGGIORNARE
Ci ho giocato per un po ', cercando un bel trucco di manipolazione, ma non sono riuscito a trovare un buon one-liner, mentre la soluzione mod 2 si inserisce in uno.
f (n) = 2n (abs (n)% 2) - n + sgn (n)
In C #, questo diventa il seguente:
public static Int32 f(Int32 n)
{
return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
Per farlo funzionare per tutti i valori, è necessario sostituirlo Math.Abs()
con (n > 0) ? +n : -n
e includere il calcolo in un unchecked
blocco. Quindi vieni persino Int.Min
mappato su se stesso come fa la negazione non selezionata.
AGGIORNARE
Ispirato da un'altra risposta, spiegherò come funziona la funzione e come costruirla.
Cominciamo dall'inizio. La funzione f
viene ripetutamente applicata a un dato valore n
producendo una sequenza di valori.
n => f (n) => f (f (n)) => f (f (f (n))) => f (f (f (f (n)))) => ...
La domanda richiede f(f(n)) = -n
, cioè due successive applicazioni di f
negare l'argomento. Altre due applicazioni di f
- quattro in totale - annullano nuovamente l'argomentazione n
.
n => f (n) => -n => f (f (f (n))) => n => f (n) => ...
Ora c'è un ovvio ciclo di lunghezza quattro. Sostituendo x = f(n)
e notando che l'equazione ottenuta f(f(f(n))) = f(f(x)) = -x
vale, si ottiene quanto segue.
n => x => -n => -x => n => ...
Quindi otteniamo un ciclo di lunghezza quattro con due numeri e i due numeri negati. Se immagini il ciclo come un rettangolo, i valori negati si trovano agli angoli opposti.
Una delle tante soluzioni per costruire un tale ciclo è la seguente a partire da n.
n => annulla e sottrai uno
-n - 1 = - (n + 1) => aggiungi uno
-n => annulla e aggiungi uno
n + 1 => sottrai uno
n
Un esempio concreto è di tale ciclo +1 => -2 => -1 => +2 => +1
. Abbiamo quasi finito. Notando che il ciclo costruito contiene un numero positivo dispari, il suo successore pari ed entrambi i numeri negano, possiamo facilmente suddividere gli interi in molti di questi cicli ( 2^32
è un multiplo di quattro) e abbiamo trovato una funzione che soddisfa le condizioni.
Ma abbiamo un problema con zero. Il ciclo deve contenere 0 => x => 0
perché zero è negato a se stesso. E poiché il ciclo afferma già 0 => x
segue 0 => x => 0 => x
. Questo è solo un ciclo di lunghezza due e x
si trasforma in se stesso dopo due applicazioni, non in -x
. Fortunatamente c'è un caso che risolve il problema. Se è X
uguale a zero otteniamo un ciclo di lunghezza uno contenente solo zero e abbiamo risolto il problema concludendo che zero è un punto fisso di f
.
Fatto? Quasi. Abbiamo 2^32
numeri, zero è un punto fisso che lascia 2^32 - 1
numeri e dobbiamo suddividere quel numero in cicli di quattro numeri. Bad che 2^32 - 1
non è un multiplo di quattro - rimarranno tre numeri non in nessun ciclo di lunghezza quattro.
Spiegherò la parte rimanente della soluzione usando l'insieme più piccolo di iteger con firma a 3 bit che vanno da -4
a +3
. Abbiamo finito con zero. Abbiamo un ciclo completo +1 => -2 => -1 => +2 => +1
. Ora costruiamo il ciclo a partire da +3
.
+3 => -4 => -3 => +4 => +3
Il problema che si pone è che +4
non è rappresentabile come numero intero a 3 bit. Otterremmo +4
negando -3
a +3
- quello che è ancora un po '3 intero valido - ma poi l'aggiunta di uno a +3
(binario 011
) produce 100
binario. Interpretato come intero senza segno, +4
ma dobbiamo interpretarlo come intero con segno -4
. Quindi in realtà -4
per questo esempio o Int.MinValue
nel caso generale è un secondo punto fisso di negazione aritmetica intera - 0
e Int.MinValue
sono mappati su loro stessi. Quindi il ciclo è in realtà il seguente.
+3 => -4 => -3 => -4 => -3
È un ciclo di lunghezza due ed +3
entra inoltre nel ciclo tramite -4
. Di conseguenza, -4
viene correttamente mappato su se stesso dopo due applicazioni, +3
viene correttamente mappato su -3
due applicazioni, ma -3
viene erroneamente mappato su se stesso dopo due applicazioni.
Quindi abbiamo costruito una funzione che funziona per tutti gli interi tranne uno. Possiamo fare di meglio? No, non possiamo. Perché? Dobbiamo costruire cicli di lunghezza quattro e siamo in grado di coprire l'intero intervallo intero fino a quattro valori. I valori rimanenti sono i due punti fissi 0
e Int.MinValue
che devono essere mappati su se stessi e due numeri interi arbitrari x
e -x
che devono essere mappati tra loro da due applicazioni di funzione.
Per mappare x
a -x
e viceversa devono formare un ciclo a quattro e devono essere posizionati in angoli opposti di tale ciclo. Di conseguenza 0
e Int.MinValue
anche agli angoli opposti. Ciò mappare correttamente x
e -x
ma scambiare i due punti fissi 0
e Int.MinValue
dopo due applicazioni funzionali e lasciarli con due ingressi fallimento. Quindi non è possibile costruire una funzione che funzioni per tutti i valori, ma ne abbiamo una che funziona per tutti i valori tranne uno e questo è il meglio che possiamo ottenere.