Esto es cierto para todos los números negativos.
f (n) = abs (n)
Debido a que hay un número negativo más que números positivos para dos enteros complementarios, f(n) = abs(n)
es válido para un caso más que una f(n) = n > 0 ? -n : n
solución que sea la misma que f(n) = -abs(n)
. Te tengo por uno ...: D
ACTUALIZAR
No, no es válido para un caso más, como acabo de reconocer por el comentario de litb ... abs(Int.Min)
simplemente se desbordará ...
También pensé en usar la información de mod 2, pero concluí que no funciona ... demasiado pronto. Si se hace correctamente, funcionará para todos los números, excepto Int.Min
porque se desbordará.
ACTUALIZAR
Jugué con él por un tiempo, buscando un buen truco de manipulación, pero no pude encontrar una buena línea, mientras que la solución mod 2 encaja en una.
f (n) = 2n (abs (n)% 2) - n + sgn (n)
En C #, esto se convierte en lo siguiente:
public static Int32 f(Int32 n)
{
return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
Para conseguir que funcione para todos los valores, tiene que sustituir Math.Abs()
con (n > 0) ? +n : -n
e incluir el cálculo en un unchecked
bloque. Luego, incluso te Int.Min
asignas a ti mismo como lo hace la negación sin control.
ACTUALIZAR
Inspirado por otra respuesta, voy a explicar cómo funciona la función y cómo construirla.
Comencemos desde el principio. La función f
se aplica repetidamente a un valor dado que n
produce una secuencia de valores.
n => f (n) => f (f (n)) => f (f (f (n))) => f (f (f (f (n))))) => ...
La pregunta exige f(f(n)) = -n
, es decir, dos aplicaciones sucesivas de f
negar el argumento. Dos aplicaciones adicionales de f
- cuatro en total - niegan el argumento nuevamente dando como resultado n
nuevamente.
n => f (n) => -n => f (f (f (n))) => n => f (n) => ...
Ahora hay un ciclo obvio de longitud cuatro. Sustituyendo x = f(n)
y observando que la ecuación obtenida se f(f(f(n))) = f(f(x)) = -x
cumple, se obtiene lo siguiente.
n => x => -n => -x => n => ...
Entonces obtenemos un ciclo de longitud cuatro con dos números y los dos números negados. Si imagina el ciclo como un rectángulo, los valores negados se encuentran en las esquinas opuestas.
Una de las muchas soluciones para construir dicho ciclo es la siguiente a partir de n.
n => negar y restar uno
-n - 1 = - (n + 1) => agregar uno
-n => negar y agregar uno
n + 1 => restar uno
norte
Un ejemplo concreto es de tal ciclo es +1 => -2 => -1 => +2 => +1
. Casi terminamos. Al observar que el ciclo construido contiene un número positivo impar, su sucesor par, y ambos números se niegan, podemos dividir fácilmente los enteros en muchos de estos ciclos ( 2^32
es un múltiplo de cuatro) y hemos encontrado una función que satisface las condiciones.
Pero tenemos un problema con cero. El ciclo debe contener 0 => x => 0
porque el cero se niega a sí mismo. Y porque el ciclo ya dice 0 => x
que sigue 0 => x => 0 => x
. Este es solo un ciclo de longitud dos y x
se convierte en sí mismo después de dos aplicaciones, no en -x
. Afortunadamente, hay un caso que resuelve el problema. Si X
es igual a cero, obtenemos un ciclo de longitud uno que contiene solo cero y resolvemos ese problema concluyendo que cero es un punto fijo de f
.
¿Hecho? Casi. Tenemos 2^32
números, el cero es un punto fijo que deja 2^32 - 1
números, y debemos dividir ese número en ciclos de cuatro números. Malo que 2^32 - 1
no es un múltiplo de cuatro: quedarán tres números que no estarán en ningún ciclo de longitud cuatro.
Explicaré la parte restante de la solución usando el conjunto más pequeño de iteradores con signo de 3 bits que van desde -4
hasta +3
. Hemos terminado con cero. Tenemos un ciclo completo +1 => -2 => -1 => +2 => +1
. Ahora construyamos el ciclo comenzando en +3
.
+3 => -4 => -3 => +4 => +3
El problema que surge es que +4
no es representable como un entero de 3 bits. Obtendríamos +4
negando -3
a +3
- lo que todavía es un número entero de 3 bits válido - pero luego sumando uno al +3
(binario 011
) los rendimientos 100
binario. Se interpreta como un entero sin signo, +4
pero tenemos que interpretarlo como un entero con signo -4
. Entonces, en realidad, -4
para este ejemplo o Int.MinValue
en el caso general, hay un segundo punto fijo de negación aritmética de enteros, 0
y Int.MinValue
se asignan a sí mismos. Entonces el ciclo es en realidad como sigue.
+3 => -4 => -3 => -4 => -3
Es un ciclo de longitud dos y además +3
ingresa al ciclo a través de -4
. En consecuencia, -4
se asigna correctamente a sí mismo después de dos aplicaciones de función, +3
se asigna correctamente -3
después de dos aplicaciones de función, pero -3
se asigna erróneamente a sí mismo después de dos aplicaciones de función.
Así que construimos una función que funciona para todos los enteros menos uno. ¿Podemos hacerlo mejor? No podemos. ¿Por qué? Tenemos que construir ciclos de longitud cuatro y podemos cubrir todo el rango entero hasta cuatro valores. Los valores restantes son los dos puntos fijos 0
y Int.MinValue
que deben asignarse a sí mismos y a dos enteros arbitrarios x
y -x
deben correlacionarse entre sí mediante dos aplicaciones de función.
Para asignar x
a -x
y viceversa deben formar un ciclo de cuatro y deben estar ubicados en las esquinas opuestas de ese ciclo. En consecuencia 0
y Int.MinValue
tiene que estar en las esquinas opuestas, también. Esto asignará correctamente x
y cambiará -x
los dos puntos fijos 0
y Int.MinValue
después de dos aplicaciones de función y nos dejará con dos entradas fallidas. Por lo tanto, no es posible construir una función que funcione para todos los valores, pero tenemos una que funciona para todos los valores excepto uno y esto es lo mejor que podemos lograr.