Isso é verdade para todos os números negativos.
f (n) = abs (n)
Como há mais um número negativo do que números positivos para dois números inteiros de complemento, f(n) = abs(n)
é válido para mais um caso que a f(n) = n > 0 ? -n : n
solução que é a mesma que f(n) = -abs(n)
. Peguei você por um ...: D
ATUALIZAR
Não, não é válido para mais um caso, pois acabei de reconhecer pelo comentário do litb ... abs(Int.Min)
apenas transbordará ...
Também pensei em usar as informações do mod 2, mas concluí que elas não funcionam ... até cedo. Se bem feito, funcionará para todos os números, exceto Int.Min
porque isso excederá.
ATUALIZAR
Eu brinquei com ele por um tempo, procurando um bom truque de manipulação, mas não consegui encontrar um bom one-liner, enquanto a solução mod 2 se encaixa em um.
f (n) = 2n (abs (n)% 2) - n + sgn (n)
Em C #, isso se torna o seguinte:
public static Int32 f(Int32 n)
{
return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
Para fazê-lo funcionar para todos os valores, você tem que substituir Math.Abs()
com (n > 0) ? +n : -n
e incluir o cálculo em um unchecked
bloco. Então você é Int.Min
mapeado para si mesmo como a negação desmarcada.
ATUALIZAR
Inspirado por outra resposta, vou explicar como a função funciona e como construí-la.
Vamos começar do começo. A função f
é aplicada repetidamente a um determinado valor, n
produzindo uma sequência de valores.
n => f (n) => f (f (n)) => f (f (f (n))) => f (f (f (f (n)))) => ...
A pergunta exige f(f(n)) = -n
, ou seja, duas aplicações sucessivas de f
negar o argumento. Duas outras aplicações f
- quatro no total - negam que o argumento volte a render-se n
novamente.
n => f (n) => -n => f (f (f (n))) => n => f (n) => ...
Agora há um ciclo óbvio de comprimento quatro. Substituindo x = f(n)
e observando que a equação obtida se f(f(f(n))) = f(f(x)) = -x
mantém, produz o seguinte.
n => x => -n => -x => n => ...
Então, temos um ciclo de comprimento quatro com dois números e os dois números negados. Se você imaginar o ciclo como um retângulo, os valores negativos estão localizados em cantos opostos.
Uma das muitas soluções para construir esse ciclo é a seguinte, partindo de n.
n => nega e subtrai um
-n - 1 = - (n + 1) => adicione um
-n => negue e adicione um
n + 1 => subtrai um
n
Um exemplo concreto é esse ciclo +1 => -2 => -1 => +2 => +1
. Estamos quase terminando. Observando que o ciclo construído contém um número positivo ímpar, seu sucessor par e ambos os números negam, podemos facilmente dividir os números inteiros em muitos desses ciclos ( 2^32
é um múltiplo de quatro) e descobrimos uma função que satisfaz as condições.
Mas temos um problema com zero. O ciclo deve conter 0 => x => 0
porque o zero é negado para si mesmo. E porque o ciclo já indica 0 => x
a seguir 0 => x => 0 => x
. Este é apenas um ciclo de comprimento dois e x
é transformado em si mesmo após duas aplicações, não em -x
. Felizmente, há um caso que resolve o problema. Se X
igual a zero, obtemos um ciclo de comprimento um contendo apenas zero e resolvemos esse problema concluindo que o zero é um ponto fixo de f
.
Feito? Quase. Temos 2^32
números, zero é um ponto fixo que deixa 2^32 - 1
números e devemos particionar esse número em ciclos de quatro números. Ruim que 2^32 - 1
não é múltiplo de quatro - restarão três números que não estão em nenhum ciclo de comprimento quatro.
Explicarei a parte restante da solução usando o conjunto menor de itegers assinados de 3 bits, que variam de -4
até +3
. Terminamos com zero. Temos um ciclo completo +1 => -2 => -1 => +2 => +1
. Agora vamos construir o ciclo começando em +3
.
+3 => -4 => -3 => +4 => +3
O problema que surge é que +4
não é representável como número inteiro de 3 bits. Nós +4
obteríamos negando -3
a +3
- o que ainda é um número inteiro válido de 3 bits - mas adicionando um a +3
(binário 011
) produz 100
binário. Interpretado como número inteiro não assinado, +4
mas temos que interpretá-lo como número inteiro assinado -4
. Portanto, na verdade, -4
para este exemplo ou Int.MinValue
para o caso geral, existe um segundo ponto fixo de negação aritmética inteira - 0
e Int.MinValue
são mapeados para eles. Portanto, o ciclo é realmente o seguinte.
+3 => -4 => -3 => -4 => -3
É um ciclo de duração dois e, adicionalmente, +3
entra no ciclo via -4
. Em conseqüência, -4
é corretamente mapeado para si mesmo após duas aplicações de funções, +3
é corretamente mapeado para -3
após duas aplicações de funções, mas -3
é erroneamente mapeado para si mesmo após duas aplicações de funções.
Então construímos uma função que funciona para todos os números inteiros, exceto um. Podemos fazer melhor? Não nós não podemos. Por quê? Temos que construir ciclos de comprimento quatro e somos capazes de cobrir todo o intervalo inteiro até quatro valores. Os valores restantes são os dois pontos fixos 0
e Int.MinValue
devem ser mapeados para si mesmos e dois números inteiros arbitrários x
e -x
que devem ser mapeados entre si por dois aplicativos de função.
Para mapear x
a -x
e vice-versa, devem formar um ciclo de quatro e que devem estar localizados em cantos opostos desse ciclo. Em conseqüência, 0
e Int.MinValue
também deve estar em cantos opostos. Isto irá mapear corretamente x
e -x
mas trocar os dois pontos fixos 0
e Int.MinValue
após duas aplicações de função e deixar-nos com duas entradas de falha. Portanto, não é possível construir uma função que funcione para todos os valores, mas temos uma que funcione para todos os valores, exceto um, e isso é o melhor que podemos alcançar.