Zdefiniuj funkcję f, tak aby f (f (n)) = -n dla wszystkich niezerowych liczb całkowitych n

43

To wyzwanie zostało zainspirowane blogiem programistycznym, który często odwiedzam. Zobacz oryginalny post tutaj: A Programming Puzzle


Wyzwanie

Zdefiniuj funkcję f:Q->Qtaką, że f(f(n)) = -ndla wszystkich niezerowych liczb całkowitych n, i gdzie Qjest zbiorem liczb wymiernych.

Detale

W jakimkolwiek języku, który preferujesz, proszę zdefiniować jedną funkcję lub program, fktóry przyjmuje jako parametr jeden numer ni zwraca lub wyprowadza jeden numer f(n).

Dane wejściowe mogą być dostarczane za pomocą dowolnego mechanizmu najbardziej naturalnego dla Twojego języka: argument funkcji, odczyt z STDIN, argument wiersza poleceń, pozycja stosu, wejście głosowe, znaki gangów itp.

Wyjście powinno być wartością zwracaną z funkcji / programu lub drukowane do STDOUT.

Chciałbym ograniczyć odpowiedzi do funkcji, które nie wykorzystują stanu programu lub globalnej pamięci / danych widocznych z zewnątrz funkcji f. Na przykład trzymanie licznika poza ftym liczy liczbę wywołań, fa samo wykonanie negacji na podstawie tej liczby nie jest bardzo trudne ani interesujące dla nikogo. Decyzje fpowinny opierać się wyłącznie na danych w fzakresie leksykalnym.

Jednak to ograniczenie jest prawdopodobnie nieodpowiednie dla niektórych języków zorientowanych na stos lub innych typów języków, które nie rozróżniają tych typów danych ani zakresów. Prosimy o dokonanie najlepszego osądu, aby zachować ducha tego wyzwania.


Punktacja

Obowiązują wspólne zasady gry w golfa - twój wynik to liczba bajtów w kodzie źródłowym.

Minimalna odpowiedź wymaga, aby domena i kodomain fbyły podzbiorem racjonalności Q. Jeśli ograniczysz swoją domenę i kodomainę fdo liczb całkowitych Z, twój wynik to pułap 90% liczby bajtów w kodzie źródłowym.

Tiebreak

W przypadku remisu zostaną użyte następujące elementy:

  1. Najmniejsza liczba drukowanych symboli spacji w kodzie źródłowym
  2. Najwcześniejsza data i godzina przesłania odpowiedzi

Edytować

Nie musisz obsługiwać liczb o dowolnych rozmiarach. Interpretuj zestawy Zi Qtypy danych w wybranym języku (zwykle odpowiednio liczby całkowite i zmiennoprzecinkowe).

Jeśli twoje rozwiązanie opiera się całkowicie na podstawowej strukturze lub strukturze bitowej typu danych, opisz jego ograniczenia i sposób użycia.

ardnew
źródło
20
f (n) = i * n - czysta matematyka: P
Johannes Kuhn
8
@JohannesKuhn właśnie dlatego domena i domena kodowa są ograniczone do racjonalnych
ardnew
Czy możesz wyjaśnić, co f:Q->Qto znaczy?
beary605
@ beary605 oznacza, że fjest funkcją mapującą członków Q(liczb wymiernych) na inne elementy (być może takie same) Q. patrz en.wikipedia.org/wiki/Function_(mathematics)#Notation
ardnew
7
Wiedziałem, że ostatnio to widziałem, ale zajęło mi to trochę czasu, żeby sobie przypomnieć, gdzie. Mniej ściśle określona wersja na StackOverflow został niedawno zamknięty. Ponad 100 odpowiedzi.
Peter Taylor

Odpowiedzi:

12

J, 9 punktów (10 znaków)

Na podstawie odpowiedzi stackoverflow :

   (*-[*_1&^)

Pierwszy pomysł (13 znaków):

   ((-*)-2&|*+:)

   ((-*)-2&|*+:) _10 _9 _8 _7 _6 _5 _4 _3 _2 _1 0 1 2 3 4 5 6 7 8 9 10
_9 10 _7 8 _5 6 _3 4 _1 2 0 _2 1 _4 3 _6 5 _8 7 _10 9

   ((-*)-2&|*+:) _9 10 _7 8 _5 6 _3 4 _1 2 0 _2 1 _4 3 _6 5 _8 7 _10 9
10 9 8 7 6 5 4 3 2 1 0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _10
randomra
źródło
Działa to na wejściu całkowitą, ale daje wyjście dla urojonego zmiennoprzecinkowych (funkcja musi produkować racjonalną produkcję racjonalnego wejściowych zgodnie spec)
zmienność
5
@ Lotność, specyfikacja jest myląca, ale gdy ją czytam, pozwala ona ograniczyć domenę i domenę kodową do liczb całkowitych.
Peter Taylor
Potrzebujesz nawiasów?
Cyoce,
14

Python: 61 34 30 29 27 punktów

f: Q -> Q

w matematyce:

       | 0.5-x   if x is in Q \ Z
f(x) = |
       | x+0.5   if x is in Z

w Pythonie:

f=lambda x:.5+[x,-x][x%1>0]

testowane z

filter(lambda n: n[0] != -n[1], map(lambda n:(n,f(f(n))),range(0,50)))

logika tego:

Gdy weźmiesz liczbę całkowitą ni włożysz ją do fsiebie, dostaniesz x+0.5. To nie jest liczbą całkowitą dłużej, więc kolejna aplikacja będzie 0.5-(x+0.5)co jest -x.

Kredyty

Dzięki

  • Bakuriu za zmniejszenie go z 61 do 34 znaków.
  • Zmienność w celu dalszego zmniejszenia rozmiaru kodu do 30 znaków.
  • kopiuj w celu zmniejszenia rozmiaru kodu do 29 znaków (i naprawienia potencjalnego problemu zmiennoprzecinkowego).
  • aditsu za wzmiankę o niespójności związanej z powyższymi zmianami.

Notatki

Najpierw pomyślałem, że będzie dobrze

f = lambda n: 1j*n

ale jego f: N-> C i to jest niedozwolone: ​​- /

Martin Thoma
źródło
1
Można go zredukować do: f=lambda x:x%1>0and(-x+x%1)or x+.1który ma tylko 34 znaki.
Bakuriu,
f=lambda x:[x+.1,x%1-x](x%1>0)jest tylko 30
Zmienność
1
Jeden char krócej: f=lambda x:[x+.5,.5-x][x%1>0]. Zwróć uwagę na użycie .5 zamiast .1 do obejścia problemów z precyzją
skopiuj
1
@AJMansfield 1.48 nie jest liczbą całkowitą.
Martin Thoma,
1
Nie, to nie znaczy, że Jeśli o tym wspomina, powinien był napisać „wszystkie liczby wymierne”. f:Q->Qoznacza tylko, że f odwzorowuje liczbę wymierną na liczby wymierne. Co robi moja definicja f.
Martin Thoma,
11

C, 41 punktów (41 lub 45 znaków)

Działa zarówno w wersji 32-, jak i 64-bitowej.

f : Z -> Z(oprócz INT_MAX):

f(n){return (abs(n)%2*2-1)*n+n?(-n<n)*2-1:0;}

Jeśli nie musimy dołączać 0, możemy ogolić niektóre znaki (41 znaków):

f : Z -> Z(z wyjątkiem 0& INT_MAX):

f(n){return (abs(n)%2*2-1)*n+(-n<n)*2-1;}

Ta funkcja polega na podzieleniu wszystkich liczb całkowitych na 4 grupy na podstawie ich znaku i parzystości.

Mamy więc 4 różne kombinacje:

+ even, + odd, - even, - odd

Ponieważ musimy zmienić znak liczby, ale nie parzystości po dwóch przejściach, otrzymujemy dwie różne możliwe sekwencje:

  + even -> - odd -> - even -> + odd -\
^-------------------------------------/

  + even -> + odd -> - even -> - odd -\
^-------------------------------------/

W tym przykładzie wybrałem pierwszy.

Najpierw musimy zmapować wszystkie parzyste dodatnie liczby całkowite na nieparzyste ujemne liczby całkowite. Robimy to, zmieniając znak i zwiększając liczbę (możesz też zamiast tego zmniejszyć liczbę):

f1(n) = -n + 1

Następnie musimy zmapować wszystkie nieparzyste ujemne liczby całkowite na nawet ujemne liczby całkowite. Musimy upewnić się, że f2(f1(n)) = -n:

f2(f1(n)) = -n
f2(-n + 1) = -n
f2(-n) = -n - 1
f2(n) = n - 1

Stosując te same metody, które znajdujemy f3i f4:

f3(n) = -n - 1
f4(n) =  n + 1

Aby połączyć te funkcje w jedną funkcję, obserwujemy, że za każdym razem nzmieniamy znak ni za każdym razem, gdy njest dodatni, zwiększamy o jedną, a w przeciwnym razie zmniejszamy o jedną:

f1(n) = -n + 1 (+ even)
f2(n) =  n - 1 (- odd)
f2(n) = -n - 1 (- even)
f4(n) =  n + 1 (+ odd)

Można to zatem przepisać jako:

f(n) = odd(n) * n + sign(n)

gdzie odd(n)zwraca 1liczby nieparzyste i -1parzyste.

Łącznie są 4 rozwiązania:

f(n) = odd(n) * n + sign(n)  (edge cases: f(f(0))  -> -2, f(f(INT_MAX))   -> -8)
f(n) = even(n) * n - sign(n) (edge cases: f(f(0))  -> -2, f(f(INT_MIN+1)) -> -6)
f(n) = odd(n) * n - sign(n)  (edge cases: f(f(1))  -> -3, f(f(INT_MIN))   -> -5)
f(n) = even(n) * n + sign(n) (edge cases: f(f(-1)) -> -1, f(f(INT_MIN))   -> -5)

INT_MINzawsze może być uważany za przypadek zbocza we wszystkich 4 funkcjach jako -INT_MIN == INT_MIN=> f(f(INT_MIN)) = INT_MIN.

Tyilo
źródło
Jest to w zasadzie to samo co moja odpowiedź na GolfScript (z wyjątkiem wyjaśnienia lepszego). Czy to działa na 0?
Ben Reich,
@BenReich Jak podano w odpowiedzi, nie działa dla 03 innych liczb.
Tyilo
1
@Tylio Widzę teraz. Ma sens. Wygląda na to, że powinieneś skorzystać z Zbonusu, jeśli pokryjesz przynajmniej 0.
Ben Reich,
@BenReich Usunąłem bonus, dopóki go nie naprawię.
Tyilo,
9

Oto mój wybór.

long f(int i){return i;}
int f(long i){return -i;}

Przykład na żywo :

int main()
{
  for(int i=-10; i<10; i=i+3)
    std::cout << f(f(i)) << "\n";
}

Typy wejściowe cn można dowolnie dostosować do własnych potrzeb. Ta wersja działa dla literałów całkowitych, które są mniejsze niż 2 ^ 32-1.

rubenvb
źródło
2
Problem powiedział f:Q->Q, nie f:Z->Z.
AJMansfield
@AJMansfield sekcja punktacji specyfikacji miała oferować punkty premiowe za zdefiniowane funkcje f:Z->Z, przepraszam za mylące sformułowanie
nowy
6
problem z tą odpowiedzią polega na tym, że wydaje się definiować dwie oddzielne funkcje, podczas gdy specyfikacja wymaga tylko zdefiniowania jednej. ale nie zamierzam rozpoczynać debaty semantyki, wciąż jest to bardzo przemyślane rozwiązanie
nowy
@ardnew, oh masz rację. Wskazano mi ten ważny sprzeciw tylko na kilka sekund przed udostępnieniem go w Lounge <C ++> na SO chat. Zastanawiam się, co robi z tego kompilator (jeśli nie wstawia wywołań), ale mój zestaw jest do kitu.
rubenvb
1
Myślę, że możesz usunąć miejsce wreturn -i
Cyoce,
6

JavaScript, 18

f=n=>n%1?.5-n:n+.5

Korzystanie z nowej notacji grubej strzałki (Firefox 22).

Inna wersja (18):

f=n=>n%1?-.5/n:.5/n

Poprzednia wersja (20):

f=n=>n-~~n?.5-n:n+.5

Przykład:

> [-3,-2,-1,1,2,3].map(f).map(f)
[3, 2, 1, -1, -2, -3]
Kopiuj
źródło
10
Wygląda na to, że JavaScript ewoluuje w CoffeeScript.
Peter Taylor
4

Mathematica 18

f=#+1/2-4#(#-⌊#⌋)&

Oto ⌊...⌋funkcja podłogi. Używa tylko liczb wymiernych (nie list, liczb zespolonych itp.)

f[10]
f[f[10]]

21/2

-10

f[-5]
f[f[-5]]

-9/2

5

Ybeltukov
źródło
3

język asemblera x86 (FASM). Argument i wynik znajdują się w rejestrze eax.

Działa poprawnie dla -2 ^ 30 <N <+ 2 ^ 30-1

16-bajtowy kod wykonywalny.

        use32

f_n:
        lea     edx, [2*eax]
        xor     edx, eax
        btc     eax, 30
        shl     edx, 1
        jnc     .end
        neg     eax
.end:
        retn
johnfound
źródło
Zbieranie numerów; 2E30 byłoby 2 * 10 ^ 30, a nie 2 ^ 30, jak myślę, że chcesz.
Nick T
@NickT Mój błąd. Naprawiony.
johnfound
Jestem pewien, że powinieneś policzyć bajty w kodzie źródłowym.
nyuszika7h
3

Common Lisp: 35 bajtów

(defun f(x)(/(if(> 1 x)-1/2 1/2)x))

Schemat (i rakieta): 36 bajtów

(define(f x)(/(if(> 1 x)-1/2 1/2)x))

Niegolfowany z komentarzami i objaśnieniami:

(define (f x)
  (/             ;; divide
     (if (> 1 x) ;; if x is below 1 
         -1/2    ;; then -1/2 (the fraction)
         1/2)    ;; else 1/2 (the fraction)
      x))        ;; gets divided with x

Na dowolny numer xw zamieni się frakcji , która jest prawdziwym dokładna liczba w obu językach.[1,->]if1/2

Część podziału stanie się wtedy, (/ 1/2 x)aby ułamek stał się 1/(x*2)zawsze poniżej 1. Bo 1tak będzie 1/2, bo 2to jest 1/4itd.

Dla dowolnej liczby poniżej 1 ifzamieni się na ułamek -1/2, co sprawia, że ​​funkcja robi (/ -1/2 x)to, co jest, -1/(2*x)ale ponieważ możemy spodziewać się, że wartość będzie wynikiem poprzedniego przebiegu, możemy podstawić x na 1 / (x * 2) wykonując podwójną aplikację-1/((1/(x*2))*2) = -x

Np. Skoro 1zamienia się 1/2w drugą aplikację to(/ -1/2 1/2) ==> -1

Sylwester
źródło
Jak to działa?
AJMansfield
@AJMansfield dodał pewne informacje. Zapytaj tylko, czy jest coś niejasnego. Czytanie składni LISP jest jak grecki, jeśli się go nie nauczyłeś i przyzwyczajanie się do niego zajmuje kilka tygodni.
Sylwester,
3

C, 60 (⌈66 * .9⌉)

int f(int x){if(!x&1||!~x)return ~x;if(x<0)return x-1;return x+1;}

Oto nieskondensowana wersja:

int f(int x){
    if(!x&1 || !~x) return ~x;
    if(x<0) return x-1;
    return x+1;
}

Ta metoda działa tylko przy użyciu liczb całkowitych, więc otrzymuje premię w wysokości 90% wyniku. Początkowo pisałem go w Javie, ale zdałem sobie sprawę, że ten program może w szczególności skorzystać z operatorów logicznych typu C.

Ponieważ nie ma liczby całkowitej odpowiadającej -INT_MIN, f(f(INT_MIN))zwraca INT_MINzamiast tego.

Podstawowe mapowanie jest algebraicznie raczej proste. Wykonanie instrukcji x=f(x)zastępuje x przez:

  • x+1, jeśli xjest dodatnia i nieparzysta
  • -x+1, jeśli xjest dodatnia i równa
  • x-1, jeśli xjest ujemne i nieparzyste
  • -x-1, jeśli xjest ujemne i parzyste

Wynik każdego przypadku znajdzie się w następnym przypadku przy następnym zastosowaniu funkcji do x.

Jak widać, komponowanie sprawy z przypadkiem następującym po niej daje wynik -x.

Kod jest wynikiem sprytnego uproszczenia funkcji, aby wykorzystać strukturę bitową liczb całkowitych komplementu dwóch.

AJMansfield
źródło
3

> <> , 21 + 3 = 24 bajty, 22 punkty

:0)$:0($:1$2%2*-*+-n;

Użyj oficjalnego interpretera języka Python i użyj -vopcji wiersza polecenia, aby wprowadzić dane wejściowe, kosztem 3 bajtów.

Mam wrażenie, że może być lepiej - będę na to patrzeć i próbować grać w golfa.

Podane dane nwyjściowe programu

(n>0) - ((n<0) + n * (1 - 2*(n%2)))

gdzie (n>0)i (n<0)są booleanami. Jest to równoważne z odpowiedzią Gelatona na Python

(n>0) - (n<0) - n * (-1)**n

ale ><>nie ma wbudowanego operatora potęgowania, więc (1 - 2*(n%2))zamiast niego używamy (-1)**n.

Poniżej znajduje się teoria matematyczna - czytaj, jeśli jesteś (i tylko jeśli) zainteresowany:

Biorąc pod uwagę żadnej funkcji f: Z -> Ztakich, że f(f(n)) = -ndla wszystkich nIN Z, widzimy od razu, że f(f(f(f(n)))) = n, innymi słowy, f^4jest to funkcja tożsamości. W szczególności fjest odwracalny, a jego funkcją odwrotną jest f^3. W ten sposób fjest permutacją Zi od tego f^4 = Idwynika, że każdy orbity (lub cykl) z fma wielkość albo 1, 2, lub 4.

Następnie widzimy to f(0) = 0. Dowód: f(0) = f(-0) = f(f(f(0))) = -f(0), więc f(0) = 0, zgodnie z życzeniem. I odwrotnie, załóżmy, że xjest w cyklu długości 1lub 2tak f(f(x)) = x. Więc -x = xtak x = 0.

Tak więc fskłada się całkowicie z 4 cykli, z wyjątkiem stałego punktu (1 cykl) przy 0.

Ponadto, każdy 4-cykl musi mieć formę (x, y, -x, -y), i obracając się wokół cyklu możemy założyć, że xi yto zarówno pozytywne. I odwrotnie, każdy taki iloczyn 4-cykli dzielących niezerowe liczby całkowite determinuje wybór f.

Zatem każdy wybór fodpowiada jednoznacznie wykresowi skierowanemu, którego wierzchołki są dodatnimi liczbami całkowitymi, tak że każdy wierzchołek pada dokładnie na jedną strzałkę, wchodząc lub wychodząc. Mówiąc ściślej, na podstawowym wykresie niekierowanym każdy wierzchołek ma dokładnie stopień 1. (W każdym cyklu 4 (x y -x -y)z xi ypozytywnych zgodny ze strzałką x --> y).

Funkcja w tej odpowiedzi (oraz kilku innych odpowiedzi tutaj) odpowiada na wykresie, gdzie 1 --> 2, 3 --> 4iw ogóle 2k-1 --> 2k.

Takie wykresy są bijection z nieskończonymi sekwencjami uporządkowanych par (a_n, p_n), gdzie każda a_njest dodatnią liczbą całkowitą, a każdy p_njest albo 0albo 1: biorąc pod uwagę sekwencję (a_1, p_1), (a_2, p_2), (a_3, p_3), ..., najpierw łączymy się 1z 1 + a_1, a następnie tworzymy strzałkę 1 --> 1 + a_1lub strzałkę w 1 + a_1 --> 1zależności od tego, czy p_1jest 0lub 1. Zasadniczo strzałka jest albo <znakiem, albo >znakiem, w zależności od parytetu p_1.

Następnie weź najmniejszą niesparowaną dodatnią liczbę całkowitą ki policz od k, dokładnie a_2kroków, POMIŃ dowolnej liczby, która jest już z czymś sparowana. Sparuj kz wynikiem i ustaw kierunek strzałki w zależności od p_2powyższego. Następnie powtórz za pomocą (a_3, p_3)itd.

Każda strzałka zostanie ostatecznie określona w ten sposób, więc proces jest dobrze zdefiniowany. Funkcja w tej odpowiedzi odpowiada sekwencji (1,0), (1,0), (1,0), ..., ponieważ na etapie nnajmniejsza niesparowana liczba całkowita jest 2n-1i nie ma liczb całkowitych większych niż 2n-1zostały sparowane z czymkolwiek, więc otrzymujemy 2n-1 --> 2ndla każdego n(strzałki są zorientowane w ten sposób, ponieważ każdy p_njest równy 0).

Liczność tego zbioru jest równa liczności liczb rzeczywistych (N*2)^N = N^Nw ostatnim akapicie tej odpowiedzi2^N .

Mathmandan
źródło
Opcje wiersza poleceń są zwykle bajtami.
kot
@cat Zobacz sekcję „Specjalne wywołania” w tym poście z meta .
matmandan
2

Aby naprawić wcześniejszą odpowiedź J (nie mam wystarczającej reputacji, aby skomentować oryginał):

(*+[*1-~2*2|])

To po prostu zastępuje _1&^się 1-~2*2|], co daje znak przeciwny. Więc zmieniłem na -a +(co ma znaczenie tylko na wejściu 1i _1).

Oto testy:

   (*+[*1-~2*2|])6 3 _9 _8 1r2 _4.6 0 1 _1
7 _2 8 _9 1 7.28 0 2 _2
   (*+[*1-~2*2|])7 _2 8 _9 1 7.28 0 2 _2
_6 _3 9 8 0 _10.3568 0 _1 1

   NB. f^:2 = f@:f
   (*+[*1-~2*2|])^:(2)6 3 _9 _8 1r2 _4.6 0 1 _1
_6 _3 9 8 2 _5.0832 0 _1 1

Jak widać, domena i zakres są liczbami rzeczywistymi, ale działa tylko dla liczb całkowitych (w tym 0).

Wyjaśnienie:

(   *     + [ *  1-~    2*     2|]    )
 signum n + n * pred (twice (n mod 2))
James Wood
źródło
2

GolfScript ceiling(26*.9)=24

Golfscript obsługuje tylko liczby całkowite, więc zastosuj Zpremię za łącznie 24 punkty:

.{..0>2*(\)2%!2*(@*+}{ }if

Specjalny przypadek 0 oznacza 8 znaków. Ignorując 0, możemy uzyskać odpowiedź 17 punktów:

..0>2*(\)2%!2*(@*+

Ten kod wykonuje następujące operacje xna liczbie całkowitej na szczycie stosu:

  • Jeśli xwynosi 0, zostaw 0na stosie i nie stosuj więcej reguł.
  • Jeśli xjest parzysty, zaneguj x.
  • Jeśli xjest dodatnia, dodaj 1.
  • Jeśli xjest ujemne, odejmij 1.

To logicznie łączy zestawy 4 liczb w cyklu, w których felementy przecinają cykl, a przeciwległe rogi cyklu są względem siebie ujemne. Każda liczba całkowita jest częścią dokładnie 1 takiego cyklu, z wyjątkiem 0, która jest przypadkiem specjalnym. Na przykład dla {-8, -7, 7, 8}:

  • 7 f -> 8
  • 8 f -> -7
  • -7 f -> -8
  • -8 f -> 7

Jedynymi istotnymi przypadkami, o których mogłem pomyśleć, były nieparzyste ujemne, parzyste ujemne, parzyste nieparzyste, parzyste dodatnie 0, a potem wrzuciłem, -1a 1ponieważ ich bliskość 0mogła powodować problemy:

[-10 -5 -1 0 1 5 10]
{.{..0>2*(\)2%!2*(@*+}{ }if}:f;
{f f}%
-> [10,5,1,0,-1,-5,-10]

Jestem pewien, że faktyczny GolfScript można nieco poprawić. Nie wydaje się, że powinno to zająć 26 znaków! Bardzo chciałbym usłyszeć kilka sugestii.

Ben Reich
źródło
2

Java, dla zabawy

Oto implementacja, która wykonuje rzeczywisty biject między ℤ i ℤ², co jest jednocześnie funkcją nieparzystą (g (-x) == -g (x)). Traktuje odpowiedni element ℤ² jako liczbę zespoloną i mnoży go przez „i”, a następnie konwertuje z powrotem na ℤ.

f (x) = g⁻¹ (ig (x))
f (f (x)) = g⁻¹ (-g (x)) = - x

Funkcja działa w O (1).

public class Ffn {
    public static int f(int n) {
        if (n == 0) {
            return 0;
        }
        // adjust sign
        int s = n > 0 ? 1 : -1;
        int m = n * s;
        // calculate square "radius"
        int r = (int) (Math.sqrt(2 * m - 1) + 1) / 2;
        int q = r * 2;
        // starting point
        int x = r, y = r;
        int k = q * (r - 1) + 1;

        if (m - k < q) {
            // go left
            x -= m - k;
        }
        else {
            // go left
            x -= q;
            // go down
            y -= m - k - q;
        }

        // multiply by i
        int x2 = -y * s, y2 = x * s;
        // adjust sign
        s = y2 < x2 || y2 == x2 && x2 < 0 ? -1 : 1;
        x2 *= s;
        y2 *= s;

        if (y2 == r) {
            // go left
            k += r - x2;
        }
        else {
            // go left and down
            k += q + r - y2;
        }
        return k * s;
    }

    public static void main(final String... args) {
        for (int i = 0; i < 1000000; ++i) {
            if (f(f(i)) != -i || f(f(-i)) != i) {
                System.out.println(i);
            }
        }
    }
}

PS Szczęśliwego Nowego Roku!

aditsu
źródło
Uważam, że białe znaki są niepotrzebne.
pppery
2

Python 3-38

Podobny do @ odpowiedź Moose, ale, f(n) == n. Działa dla wszystkich wartości całkowitych.

f=lambda x:x*(isinstance(x,int)*2.0-1)
cjfaure
źródło
2

Perl, 33 (bez białych znaków)

sub f{($=)=@_;$=-$_[0]?-$=:"$=.1"}

Edytować:

  • $=.".1"skrócone do "$=.1"(dzięki ardnew).

Matematyka:

Matematyka

Nie golfowany:

# script.pl
sub f {
  ($=) = @_;   # short for $= = int($_[0]); 
               # "int" is implicit in assignments to $=;
               # ($=) can be prepended by "local" to get
               # the function free of side effects.

  $= - $_[0] ? # short for $= != $_[0], check if input is integer
    -$=        # input is not an integer  
  : $= . ".1"  # input is integer
}  

# Testing
chomp;
$_ = sprintf "f(f($_)) = f(%s) = %s\n", f($_), f(f($_));

Przykłady:

perl -p script.pl
7
f(f(7)) = f(7.1) = -7
2
f(f(2)) = f(2.1) = -2
0
f(f(0)) = f(0.1) = 0
-1
f(f(-1)) = f(-1.1) = 1
-10
f(f(-10)) = f(-10.1) = 10
-1.23
f(f(-1.23)) = f(1) = 1.1
3.4
f(f(3.4)) = f(-3) = -3.1
1.0
f(f(1.0)) = f(1.1) = -1
Heiko Oberdiek
źródło
solidne rozwiązanie - zmiennoprzecinkowe przypadki testowe, które demonstrowałeś, nie są wymagane według specyfikacji (powinny były oferować za to punkty bonusowe!). oto twój ten sam algorytm z kilkoma oczyszczeniami nadchodzącymi z 22 sub f{yzxzzc?-$_:x.$_}
znakami
1
@ardnew: Dzięki. Ale nie zgadzam się, że twoje rozwiązanie używa tego samego algorytmu. Algorytm niesub f{yzxzzc?-$_:x.$_} jest wolny od stanu, wykorzystuje stan za pośrednictwem zmiennej . Z tego powodu nie jest już funkcją (w sensie matematycznym), ponieważ możliwe są różne wartości dla tej samej wartości wejściowej w zależności od stanu (pogoda zawiera lub nie). Mój algorytm nie używa stanu. Informacja jest zakodowana w wartości wyjściowej. Dodając, liczby całkowite są konwertowane na liczby rzeczywiste . A liczby rzeczywiste są konwertowane z powrotem na liczby całkowite z przełączonym znakiem. $_f$_x.1
Heiko Oberdiek
ciekawe - żadne dane stanu nie są używane w implementacji z powodu początkowego przypisania, a nie z powodu jakiejś specjalnej właściwości $=?
nowy
nie zdawałem sobie sprawy, że również nie spełniłem własnych wymagań (które fnależy zdefiniować Q->Q) dla tego xznaku. $=.".1"można również skrócić do"$=.1"
nowego
@ardnew: Specjalną właściwością $=jest to, że pobiera tylko liczby całkowite. To samo można osiągnąć za pomocą zwykłej zmiennej: $a=int$_[0]. Ale to kosztuje trzy dodatkowe bajty z powodu funkcji int.
Heiko Oberdiek
2

Julia, 26 lat

julia> f(n::Int)=n//1
f (generic function with 1 method)
julia> f(n)=int(-n)
f (generic function with 2 methods)
julia> f(f(4))
-4

Niezbyt konkurencyjny, ale bardzo Juliański, ponieważ polega na wielokrotnej wysyłce. Po prostu czyni na Rational, jeśli jest to Int, lub int ze znakiem minus, jeśli jest to coś innego. Można by sprzeciwić się, że są to 2 funkcje, ale Julia uważa, że ​​jest to jedna funkcja z dwiema metodami i jest to równoważne z definicją jednej funkcji z instrukcją if dla typu n.

gggg
źródło
Matematyk nie nazwałby funkcji: w Julii 3==3//1wraca, trueale f(3//1)==f(3)wraca false.
Omar
2

Cukierki , 20 18 bajtów

Używa sztuczki 3 -> 4 -> -3 -> -4 -> 3.

~A2%{|m}1A0>{+|-}.

Aby go wywołać, użyj przełącznika -i na tłumaczu

Przykład podwójnego wywołania:

$ candy -i 7 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> 8
$ candy -i 8 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> -7
$ candy -i -7 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> -8
$ candy -i -8 -e '~A2%{|m}1A0>{+|-}.'
program length: 18
>>> 7

Długa forma:

peekA
pushA
digit2
mod          # even/odd
if
else
  negate     # negate even numbers
endif
digit1
pushA
digit0
greater      # positive/negative
if
  add        # add two numbers from stack (original stack value, and delta)
else
  sub        # diff two numbers from stack (original stack value, and delta)
endif
retSub
Dale Johnson
źródło
2

Dyalog APL, 9 punktów

×-⍨⊢ׯ1*⊢

Źródło ma długość 9 bajtów i kwalifikuje się do premii (co wcale nie pomaga). Wykorzystuje również formułę z górnej odpowiedzi SO.

lirtosiast
źródło
1

GTB , 22

@S;N,"--$x?N)→N~N#~-N&
Timtech
źródło
1

Java, 113 bajtów

Podejście jest dość proste. Skończyło się to na większej liczbie bajtów, niż się spodziewałem, ale być może można trochę pograć w golfa.

public class F{public static int f(int x){if(x<0)x+=-2147483647-++x;x+=1073741824;return x<0?-2147483647-++x:x;}

Zasadniczo tworzy 4 różne „obszary” x, wykorzystując fakt, że Java szczęśliwie pozwala na zawijanie zmiennych. Musiałem wykonać trudną konwersję liczb ujemnych, co jest głównym powodem, dla którego skończyło się to na więcej niż oczekiwano.

Działa dla wszystkich x oprócz -2147483648.

FIQ
źródło
1

Ta sama sekwencja liczb (3, 4, -3, -4, 3 ...) jak odpowiedź na skrypt golfowy, ale zaimplementowana w perlu (42 znaki po usunięciu białych znaków)

sub f{($_[0]%2?1:-1)*$_[0]+($_[0]<0?-1:1)}

Bardziej czytelnie:

sub f { ($_[0] % 2 ? $_[0] : -$_[0] ) + ( $_[0] < 0 ? -1 : 1 ) }

Lub jeszcze bardziej czytelnie:

sub f {
  my $n = shift;
  my $sign = $n >= 0 ? 1 : -1;
  # note that in perl $n % 2 is the same as int($n) % 2
  if( $n % 2 ) {
    # odd: add one to magnitude
    return $n + $sign
  } else {
    # even: subtract one from magnitude then invert
    return -($n - $sign)
  }
}

Wynik:

ski@anito:~/mysrc/.../acme$ echo 3 | perl -e 'sub f{($_[0]%2?1:-1)*$_[0] + ($_[0]<0?-1:1)}; my $x = <>; for(0..10) { print "$_: $x\n"; $x = f($x); }'
0: 3
1: 4
2: -3
3: -4
4: 3
5: 4
6: -3
7: -4
8: 3
9: 4
10: -3
skibrianski
źródło
Powyższe działa również w przypadku liczb całkowitych: ski @ anito: ~ / mysrc /.../ acme $ echo 1.1234 | perl -e 'sub f {($ _ [0]% 2? 1: -1) * $ _ [0] + ($ _ [0] <0? -1: 1)}; my $ x = <>; for (0..4) {print "$ _: $ x \ n"; $ x = f ($ x); } '0: 1.1234 1: 2.1234 2: -1.1234 3: -2.1234 4: 1.1234
skibrianski
1

Sed, 25 bajtów.

|sed s/0+/0-/|sed s/^/0+/

Stosowanie:

$ echo 1.23 |sed s/0+/0-/|sed s/^/0+/
0+1.23
$ echo 0+1.23 |sed s/0+/0-/|sed s/^/0+/
0+0-1.23
Ken A.
źródło
1

Matlab, 26 znaków

f=@(n) (n<0)-(n<0)-n*(-1)^n
bla
źródło
2
To nie jest poprawna odpowiedź, ponieważ domena i kodomena funkcji nie mogą być złożone.
Wrzlprmft
och, przepraszam ... Właśnie przeczytałem tytuł i nie byłem zbyt ostrożny ... Zobaczmy, czy mogę to nieco edytować
bla
1

C ++ - 63 55,8

Oto jak wygląda kod:

int f(int n){return (n&45056?n^45056:n|45056)*(n&45056?-1:1);}

Nie działa na liczbach całkowitych, których czwarty bajt jest równy 0xB, ponieważ używa tej wartości do śledzenia przebiegów. W przeciwnym razie działa na dowolnym elemencie Z, w tym na zero.

Darkgamma
źródło
możesz to wyjaśnić? przy pierwszej inspekcji wygląda na to, że prowadzisz licznik połączeń do fzmiennej statycznej. ale jaki jest sens tego sqrt?
nowy
Wydaje mi się, że źle zrozumiałem pytanie; myślałem, że zmienna statyczna jest w porządku, ponieważ C ++ jest językiem zorientowanym na stos, ale naprawię kod. W przeciwnym razie nie mam pojęcia, dlaczego potrzebowałem, sqrtponieważ i tak zaokrągla się w dół za pomocą rzutowania typu. Zmienię to tak, aby działało bez zmiennej statycznej.
Darkgamma,
Nie mam pojęcia, skąd masz 55.8, ale twój obecny kod ma 62 bajty. Edycja: Nieważne, nie przeczytałem poprawnie pytania.
nyuszika7h
Ograniczenie, że czwarty bajt nie może być równy 0xB, niestety sprawia, że ​​nie jest to poprawna odpowiedź na wyzwanie, które wymaga, aby działał on na (co najmniej) wszystkich liczbach całkowitych.
pppery
1

Zaktualizowany o funkcję dostarczoną przez Synthetica (oczywiście ten, który powinien uzyskać teraz kredyt)

Język: Python

Liczba znaków: 41 w tym białe znaki

f=lambda x:-float(x) if str(x)==x else`x`
HolySquirrel
źródło
Podaj także nazwę używanego języka i podaj liczbę znaków.
ProgramFOX,
Podoba mi się, jak to działa również w przypadku liczb całkowitych. Dobra robota. :)
cjfaure
f=lambda x:-float(x) if str(x)==x else`x`jest nieco krótszy: 41 w tym białe spacje
25ıʇǝɥʇuʇǝɥʇs
Dzięki Synthetica, nawet nie wiedziałem o sztuczce backticks! : D
HolySquirrel
Na liczbach całkowitych fzwraca ciąg; specyfikacja mówi, że musi zwrócić liczbę wymierną.
Omar
1

Prolog, 36 bajtów

Kod:

X*Y:-X//1=:=X,Y is 0.5+X;Y is 0.5-X.

Wyjaśniono:

Dyadic predicate which converts integers to floats and floats back to negated integers.

Przykład:

10*X.
X = 10.5

10*Y,Y*X.
X = -10,
Y = 10.5
Emigna
źródło
1

JavaScript ES6, 27 26 bajtów

a=>a%1?-Math.floor(a):a+.2
SuperJedi224
źródło
1

Mysz-2002 , 21 19 12 bajtów

$A1%[1%_|1%]

Definiuje funkcję A; nazwij to jak #A,#A,?;;(co będzie czekać, aż użytkownik wprowadzi dowolny numer). Możesz też nazwać to tak, #A,#A,n;;gdzie njest dowolny numer.

kot
źródło
1

Julia, 21 lat

f(x)=(1-2(1>x>-1))/2x

Następnie

julia> f(f(12//1))
-12//1

p // q to dosłowny zapis liczb wymiernych Julii.

mschauer
źródło