Это верно для всех отрицательных чисел.
f (n) = abs (n)
Поскольку существует еще одно отрицательное число, чем положительное число для целых чисел, дополняющих двойку, f(n) = abs(n)
оно действительно для еще одного случая, чем f(n) = n > 0 ? -n : n
решение, которое совпадает с f(n) = -abs(n)
. Получил тебя по одному ...: D
ОБНОВИТЬ
Нет, это не действительно для одного случая больше, поскольку я только что узнал по комментарию Литба ... abs(Int.Min)
просто переполнится ...
Я тоже думал об использовании информации о моде 2, но пришел к выводу, что она не работает ... до раннего. Если все сделано правильно, это будет работать для всех чисел, за исключением того, Int.Min
что это будет переполнено.
ОБНОВИТЬ
Я поиграл с ним некоторое время, ища хороший трюк с манипуляциями, но я не мог найти хороший однострочный, в то время как решение для мод 2 вписывается в один.
f (n) = 2n (abs (n)% 2) - n + sgn (n)
В C # это становится следующим:
public static Int32 f(Int32 n)
{
return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
Для того, чтобы получить его работу для всех значений, вы должны заменить Math.Abs()
с (n > 0) ? +n : -n
и включают в расчет в качестве unchecked
блока. Тогда вы даже Int.Min
сопоставлены с самим собой, как непроверенное отрицание.
ОБНОВИТЬ
Вдохновленный другим ответом, я собираюсь объяснить, как работает функция и как ее создать.
Давайте начнем с самого начала. Функция f
неоднократно применяется к заданному значению, n
давая последовательность значений.
n => f (n) => f (f (n)) => f (f (f (n))) => f (f (f (f (n)))) => ...
Вопрос требует f(f(n)) = -n
, чтобы это было два последовательных применения f
отрицания аргумента. Два дальнейших применения f
- всего четыре - снова сводят на нет аргумент и снова дают результат n
.
n => f (n) => -n => f (f (f (n))) => n => f (n) => ...
Теперь существует очевидный цикл длины четыре. Подставляя x = f(n)
и отмечая, что полученное уравнение f(f(f(n))) = f(f(x)) = -x
выполнено, получаем следующее.
n => x => -n => -x => n => ...
Таким образом, мы получаем цикл длиной четыре с двумя числами и двумя числами с отрицанием. Если вы представляете цикл как прямоугольник, отрицательные значения расположены в противоположных углах.
Одним из многих решений для построения такого цикла является следующее, начиная с п.
n => отрицать и вычесть один
-n - 1 = - (n + 1) => добавить один
-n => отменить и добавить один
n + 1 => вычесть один
N
Конкретный пример такого цикла есть +1 => -2 => -1 => +2 => +1
. Мы почти закончили. Отмечая, что построенный цикл содержит нечетное положительное число, его четный преемник и оба числа отрицательные, мы можем легко разделить целые числа на множество таких циклов ( 2^32
кратных четырем) и найти функцию, которая удовлетворяет условиям.
Но у нас проблема с нулем. Цикл должен содержать, 0 => x => 0
потому что ноль отрицается сам по себе. И потому что цикл состояний уже 0 => x
это следует 0 => x => 0 => x
. Это всего лишь цикл длины два, и x
он превращается в себя после двух применений, а не в -x
. К счастью, есть один случай, который решает проблему. Если X
равен нулю, мы получаем цикл длины один, содержащий только ноль, и мы решили эту проблему, заключив, что ноль является фиксированной точкой f
.
Выполнено? Почти. У нас есть 2^32
числа, ноль - фиксированная точка, оставляющая 2^32 - 1
числа, и мы должны разбить это число на циклы из четырех чисел. Плохо, что 2^32 - 1
не кратно четырем - останется три числа не в любом цикле длины четыре.
Я объясню оставшуюся часть решения, используя меньший набор 3-битных подписанных итераторов в диапазоне от -4
до +3
. Мы сделали с нуля. У нас есть один полный цикл +1 => -2 => -1 => +2 => +1
. Теперь давайте построим цикл, начинающийся с +3
.
+3 => -4 => -3 => +4 => +3
Проблема, которая возникает, состоит в том, что +4
не представляется как 3-битное целое число. Мы получили бы +4
отрицая , -3
чтобы +3
- то , что до сих пор действует 3 разрядное целое число - но добавление одного к +3
(двоичный 011
) дает 100
бинарной. Он интерпретируется как целое число без знака, +4
но мы должны интерпретировать его как целое число со знаком -4
. Так что на самом деле -4
для этого примера или Int.MinValue
в общем случае это вторая фиксированная точка целочисленного арифметического отрицания - 0
и Int.MinValue
отображаются на себя. Таким образом, цикл на самом деле выглядит следующим образом.
+3 => -4 => -3 => -4 => -3
Это цикл длины два и дополнительно +3
входит в цикл через -4
. В результате -4
правильно отображается на себя после двух приложений функции, +3
правильно отображается -3
после двух приложений функции, но -3
ошибочно отображается на себя после двух приложений функции.
Итак, мы создали функцию, которая работает для всех целых чисел, кроме одного. Можем ли мы сделать лучше? Нет мы не можем. Почему? Мы должны построить циклы длины четыре и иметь возможность охватить весь диапазон целых чисел до четырех значений. Остальные значения являются две неподвижными точками , 0
и Int.MinValue
которые должны быть отображены на себя и два произвольных целые числа x
и -x
которые должны быть отображены друг с другом с помощью двух приложений функции.
Чтобы отобразить x
на -x
и наоборот , они должны образовывать четыре цикла , и они должны быть расположены на противоположных углах этого цикла. В следствии 0
и Int.MinValue
должны быть на противоположных углах тоже. Это будет правильно карту x
и -x
но поменять местами две фиксированные точки 0
и Int.MinValue
после двух применений функции и оставить нас с двух провальных входов. Таким образом, невозможно создать функцию, которая работает для всех значений, но у нас есть такая, которая работает для всех значений, кроме одного, и это лучшее, чего мы можем достичь.