Bounce-modulo dwie liczby

12

Wykres operacji modulo ( y=xmodk ) wygląda następująco:

Wykres funkcji modulo

Jest to bardzo przydatna funkcja, ponieważ pozwala nam tworzyć zachowanie „zawijające”. Jest to jednak bardzo kłopotliwe, gdy chcę go użyć do stworzenia efektu „odbijania się” między dwiema ścianami. Wykres funkcji „odbicia” ( y=bounce(x,k) ) wygląda następująco:

Wykres funkcji „bounce-modulo”

Okres od wykresu znaczy . Okres wykresu wynosi , ponieważ przesuwa się w górę o jednostek, a następnie przesuwa się w dół o kolejne jednostek, zanim powróci do miejsca, w którym się zaczął. W przypadku obu funkcji minimalna wartość dla wynosi 0, a maksymalna to (w rzeczywistości dla funkcji modułu ze zintegrowanymi wejściami jest to ). Ponadto dla obu funkcji wartość, gdzie wynosi 0.k y = odbicie ( x , k ) 2 k k k y k k - 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

Wyzwanie

Biorąc pod uwagę liczbę całkowitą i dodatnią liczbę całkowitą , zwróć przybliżoną liczbę całkowitą lub zmiennoprzecinkową .k y = odbicie ( x , k )xky=bounce(x,k)

To jest , więc wygrywa najkrótsze prawidłowe zgłoszenie (liczone w bajtach).

Przypadki testowe

  x,  k -> bounce(x, k)
  0, 14 ->            0
  3,  7 ->            3
 14, 14 ->           14
 15, 14 ->           13
-13, 14 ->           13 (12.999997 etc would be an acceptable answer)
-14, 14 ->           14
191,  8 ->            1
192,  8 ->            0

Dodatkowe punkty dla Fouriera -na podejście Fouriera .

Esolanging Fruit
źródło
Dla obu funkcji minimalna wartość x wynosi 0, a maksymalna to k ” jest po prostu błędna.
Peter Taylor
@PeterTaylor Whoops. Mam na myśli wynik.
Esolanging Fruit 16.07.17
1
Ups, tak już myślałem. Nadal jest źle. k % k = 0
Peter Taylor
@PeterTaylor Oh, rozumiem twoje pytanie. Pierwotnie zaprojektowałem to z myślą o liczbach zmiennoprzecinkowych, a potem przestawiłem się na ints później. Będzie edytować.
Esolanging Fruit 16.07.17
1
@PeterTaylor Jeśli argumentami są liczby zmiennoprzecinkowe, maksymalna to liczba dowolnie bliska k.
Esolanging Fruit

Odpowiedzi:

7

Kod maszynowy x86-64, 18 bajtów

97
99
31 D0
29 D0
99
F7 FE
29 D6
A8 01
0F 45 D6
92
C3 

Ten kod definiuje funkcję obliczającą się w języku maszynowym x86-64 bounce(x, k). Zgodnie z konwencją wywoływania AMD64 w Systemie V stosowaną w systemach Gnu / Unix, xparametr jest przekazywany do EDIrejestru, podczas gdy kparametr jest przekazywany do ESIrejestru. Podobnie jak w przypadku wszystkich konwencji wywoływania x86, wynik jest zwracany do EAXrejestru.

Aby wywołać to z C, prototypujesz go w następujący sposób:

int Bounce(int x, int k);

Wypróbuj online!

Mnemoniki do montażu bez golfa:

; Take absolute value of input 'x' (passed in EDI register).
; (Compensates for the fact that IDIV on x86 returns a remainder with the dividend's sign,
; whereas we want 'modulo' behavior---the result should be positive.)
xchg   eax, edi      ; swap EDI and EAX (put 'x' in EAX)
cdq                  ; sign-extend EAX to EDX:EAX, effectively putting sign bit in EDX
xor    eax, edx      ; EAX ^= EDX
sub    eax, edx      ; EAX -= EDX

; Divide EDX:EAX by 'k' (passed in ESI register).
; The quotient will be in EAX, and the remainder will be in EDX.
; (We know that EAX is positive here, so we'd normally just zero EDX before division,
; but XOR is 2 bytes whereas CDQ is 1 byte, so it wins out.)
cdq
idiv   esi

; Pre-emptively subtract the remainder (EDX) from 'k' (ESI),
; leaving result in ESI. We'll either use this below, or ignore it.
sub    esi, edx

; Test the LSB of the quotient to see if it is an even number (i.e., divisible by 2).
; If not (quotient is odd), then we want to use ESI, so put it in EDX.
; Otherwise (quotient is even), leave EDX alone.
test   al, 1
cmovnz edx, esi

; Finally, swap EDX and EAX to get the return value in EAX.
xchg   eax, edx
ret

Zauważ, że pierwsza sekcja (która przyjmuje wartość bezwzględną) mogła zostać napisana w równoważny sposób:

; Alternative implementation of absolute value
xchg    eax, edi
neg     eax
cmovl   eax, edi

która jest dokładnie taką samą liczbą bajtów (6). Wydajność powinna być podobna, być może nieco szybsza (z wyjątkiem niektórych układów Intel, w których ruchy warunkowe są powolne ).

XCHGjest oczywiście stosunkowo wolny i nie byłby preferowany, z MOVwyjątkiem kodowania w golfa (ten pierwszy ma 1 bajt, gdy jednym z operandów jest akumulator, podczas gdy rejestr rejestru MOVma zawsze 2 bajty).

Cody Gray
źródło
6

Galaretka , 3 bajty

æ%A

Wypróbuj online!

Wbudowane ftw.

Wyjaśnienie

æ%jest przydatnym wbudowanym tutaj. Nie wiem, jak to opisać, więc przedstawię dane wyjściowe dla niektórych danych wejściowych:

Gdy xidzie od 0nieskończoności, xæ%4idzie 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)tam , gdzie część w nawiasach jest powtarzana do nieskończoności w obie strony.

Leaky Nun
źródło
3

Rubinowy, 40 bajtów 32 bajty

b=->(x,k){(x/k+1)%2>0?x%k:k-x%k}

Wypróbuj online!

Wyjaśnienie

Cześć, to moja pierwsza odpowiedź na tej stronie! Ten kod opiera się na spostrzeżeniu, że funkcja odbicia zachowuje się dokładnie tak jak modulo, gdy ( n -1) k <= x < nk i n jest nieparzysta, i zachowuje się jak odwrócona operacja modulo, gdy n jest parzyste. (x/k+1)jest najmniejszą liczbą całkowitą większą niż x / k (która jest x / k +1 zaokrąglona w dół do liczby całkowitej). Dlatego (x/k+1)znajduje n wspomniane powyżej. %2>0sprawdza, czy n jest nieparzyste, czy parzyste. Jeśli n mod 2> 0, to n jest nieparzyste. Jeśli nmod 2 = 0, a następnie n jest parzyste. Jeśli n jest nieparzyste, funkcja odbicia powinna wynosić x mod k . Jeśli n jest parzyste, funkcja odbicia powinna być odwrotna, równa k - x mod k . Całe wyrażenie (x/k+1)%2>0?x%k:k-x%kznajduje n , a następnie wykonuje x mod k, jeśli jest nieparzyste, i wykonuje k - x mod k w przeciwnym razie.

Odpowiedź została poprawiona na podstawie sugestii Cyoce .

CyborgOctopus
źródło
Możesz przekonwertować to na lambda. Zamiast def b(x,k) ... endużycia->x,k{...}
Cyoce,
A ponieważ masz do czynienia z liczbami całkowitymi, .to_inie jest to konieczne.
Cyoce,
2

Mathematica, 19 bajtów

Abs@Mod[#,2#2,-#2]&
alephalpha
źródło
1

J, 25 bajtów

Wskazówka:

To tylko zwykłe modulo na liczbach drabinkowych. Na przykład w przypadku 5:0 1 2 3 4 5 4 3 2 1

Oto (jeszcze niezbyt dobrze zagrane) rozwiązanie w J. Postaram się poprawić jutro:

[ ((|~ #) { ]) (i.@>:,}:@i.@-) @ ]

sprężony: [((|~#){])(i.@>:,}:@i.@-)@]

skompresowany2: [((|~#){])(<:|.|@}.@i:)@]

Wypróbuj online!

Jonasz
źródło
Wydaje mi się, że i:można go tutaj wykorzystać, ale nie próbowałem jeszcze rozwiązania
Conor O'Brien
@ ConorO'Brien sprawdź moją wersję skompresowaną2, oszczędza kilka bajtów przy użyciu i:. Po prostu nie miałem czasu na aktualizację głównego i wyjaśnienie. Oczekuję, że ekspert mógłby ogolić kolejne 4 lub 5 bajtów przynajmniej ...
Jonasz
((|~#){])]-|@}:@i:przez 18 bajtów
mile
@miles beautiful, tyvm
Jonah
1

QBIC , 25 30 27 bajtów

g=abs(:%:)~a'\`b%2|?b-g\?g

Czy trochę restrukturyzacji ...

Wyjaśnienie

g=abs(   )  let g be the absolute value of 
       %    the (regular) modulo between
      : :   input a read from cmd line, and input b read from cmd line
~a \ b%2    IF the int division of A and B mod 2 (ie parity test) yields ODD
  ' `         (int divisions need to be passed to QBasic as code literals, or ELSE...)
|?b-g       THEN print bouncy mod
\?g         ELSE print regular mod
Steenbergh
źródło
Czy QBIC robi coś innego dla operacji MOD niż inne podstawowe implementacje? Inne podstawy zwracają MOD z tym samym znakiem, co dywidenda; że zawiedzie, gdy xjest -13 i kjest 14.
Cody Grey
@CodyGray Nope, dał -13. Naprawiono teraz.
steenbergh
Nie potrzebujesz absobu razy?
Neil
@ Nee, czy masz na to próbę?
steenbergh
@Neil nvm, naprawiłem to, restrukturyzując całość.
steenbergh
1

C89, 40 bajtów

t;f(x,k){t=abs(x%k);return x/k%2?k-t:t;}

Port AC mojej odpowiedzi na kod maszynowy x86 , to definiuje funkcję f, która oblicza moduł bounce dla parametrów xi k.

Korzysta z reguły C89 niejawnej, dzięki czemu oba parametry, zmienna globalna ti wartość zwracana przez funkcję są niejawnie typu int. Zmienna globalna tjest po prostu używana do przechowywania wartości tymczasowej, która kończy oszczędzanie bajtów, w porównaniu do powtarzania obliczeń po obu stronach operatora warunkowego.

absFunction (wartość bezwzględna) jest zaopatrzona w <stdlib.h>nagłówku, ale nie muszą zawierać tutaj, znowu dzięki niejawny-int reguły C89 jest (gdy funkcja jest niejawnie zadeklarowanej i zakładanym do zwrotu int).

Wypróbuj online!

Wersja bez golfa:

#include <stdlib.h>

int Bounce(int x, int k)
{
    int mod = abs(x % k);
    return (x/k % 2) ? k-mod : mod;
}

Patrząc na to w świetle mojego ręcznie dostosowanego kodu maszynowego , kompilatory faktycznie generują całkiem niezłą wydajność . Mam na myśli, że powinni; jest to dość prosta funkcja do optymalizacji! Odkryłem jednak drobny błąd w optymalizatorze x86-64 GCC , gdzie ciekawie generuje większy kod, gdy każesz mu zoptymalizować rozmiar i mniejszy kod, gdy mówisz, żeby zoptymalizować szybkość .

Cody Gray
źródło
m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}jest krótszy
użytkownik41805
Tyle że w rzeczywistości nie zwraca wartości @cows, inaczej niż w pewnych źle zdefiniowanych okolicznościach z powodu dziwactwa generatora kodu GCC na obiektach x86. Widzę, że ludzie używają tutaj tego szablonu, ale dla mnie to nie działa, podobnie jak wyciąganie losowych śmieci ze stosu, który akurat jest poprawną odpowiedzią.
Cody Gray,
1

Haskell, 37 bajtów

Wypróbuj online!

(!)=mod;x#k|odd$x`div`k=k-x!k|1<2=x!k

Sposób użycia:
połączenia jak 15#14za nieujemnych pozostawionych argumentów i jak (-13)#14dla negatywu lewo argumenty, ponieważ Haskell byłoby interpretować -13#14jako -(13#14)jeśli używasz coś podobnego ghci. Łącze TIO po prostu przyjmuje dwa argumenty wiersza poleceń.

Objaśnienie:
Najpierw redefiniuje binarny operator poprawki, !aby był taki sam jak mod. Haskell modzawsze generuje wartość nieujemną, więc nie potrzebujemy tego abs, co robią inne rozwiązania. Następnie sprawdza, czy x/k(dzielenie liczb całkowitych) jest nieparzyste, a jeśli tak, zwraca k-x mod k(tj. Odskok wsteczny) lub zwraca x mod k.

SEJPM
źródło
Prawdopodobnie jest to tylko kwestia gustu, ale ja osobiście wolę nie definiować, !ponieważ nie oszczędza to więcej bajtówx#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Mark S.,
1

PHP, 40 50 bajtów

cholerne dolary. cholerny narzut z importu. :)

wersja całkowita:

[,$x,$k]=$argv;$y=abs($x)%$k;echo$x/$k&1?$k-$y:$y;

lub

[,$x,$k]=$argv;echo[$y=abs($x)%$k,$k-$y][$x/$k&1];

wersja zmiennoprzecinkowa, 56 bajtów:

Wymień abs($x)%$księ fmod(abs($x),$k).


edycja: poprawiono wyniki dla negatywnych x

Tytus
źródło
4
„Cholerne dolary”. Tak, pieniądze śmierdzą ...
steenbergh
2
Co powiesz na €argvlub £argv? Wyglądałyby ładnie: x
Ismael Miguel
1

JavaScript (ES6), 36 32 bajtów

k=>f=x=>x<0?f(-x):x>k?k-f(k-x):x

Rekurencyjnie odbija się xod 0i ktak bardzo w duchu wyzwania.

Neil
źródło
0

Common Lisp, 41 bajtów

(lambda(x k)(- k(abs(-(mod x(* k 2))k))))

Wypróbuj online!

Renzo
źródło
0

C (gcc), 43 53 bajtów

Edycja: Naprawiono negatywny problem

int f(int x,int y){return x/y%2?abs(y-x%y):abs(x%y);}

Wypróbuj online!

Zachary Cotton
źródło
2
To daje złą odpowiedź na (-13, 14) (-13 zamiast 13). Moduł i pozostałe operacje zachowują się inaczej na liczbach ujemnych.
97 CAD
0

R, 28 bajtów

pryr::f(abs((x-k)%%(2*k)-k))

Który ocenia się na funkcję:

function (k, x) 
abs((x - k)%%(2 * k) - k)

Która wydaje się być metodą używaną przez większość rozwiązań. Nie patrzyłem na nie przed zrobieniem tego.

JAD
źródło