Bounce-modulo deux nombres

12

Le graphique de l'opération modulo ( y=xmodk ) ressemble à ceci:

Graphique de la fonction modulo

Il s'agit d'une fonction très utile, car elle nous permet de créer un comportement "enveloppant". Cependant, c'est très lourd quand je veux l'utiliser pour créer une apparence de "rebond" entre deux murs. Le graphique de la fonction "rebond" ( y=bounce(x,k) ) ressemble à ceci:

Graphique de la fonction "bounce-modulo"

La période du graphe de est . La période du graphique de est de , car elle monte vers le haut pour unités, puis descend vers le bas pour autres unités, avant de revenir à son point de départ. Pour les deux fonctions, la valeur minimale pour est 0 et la valeur maximale est (en fait, pour la fonction module avec entrées intégrales, c'est ). De plus, pour les deux fonctions, la valeur où est 0.k y = rebond ( x , k ) 2 k k k y k k - 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

Le défi

Étant donné un entier et un entier positif , renvoyer une approximation entière ou à virgule flottante de .k y = rebond ( x , k )xky=bounce(x,k)

Il s'agit de , donc la soumission valide la plus courte (comptée en octets) l'emporte.

Cas de test

  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

Les points bonus pour une Fourier -Basé approche de Fourier .

Esolanging Fruit
la source
" Pour les deux fonctions, la valeur minimale de x est 0 et la valeur maximale de k " est tout simplement faux.
Peter Taylor
@PeterTaylor Whoops. Je veux dire le résultat.
Esolanging Fruit
1
Oups, c'est ce que je pensais déjà dire. C'est toujours faux. k % k = 0
Peter Taylor
@PeterTaylor Oh, je comprends votre question. J'avais à l'origine conçu cela avec une virgule flottante à l'esprit, puis je suis passé à seulement des pouces après. Va éditer.
Esolanging Fruit
1
@PeterTaylor Si les arguments sont des flottants, alors le maximum est un nombre arbitrairement proche de k.
Esolanging Fruit

Réponses:

7

Code machine x86-64, 18 octets

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

Ce code définit une fonction en langage machine x86-64 qui calcule bounce(x, k). Conformément à la convention d'appel System V AMD64 utilisée sur les systèmes Gnu / Unix, le xparamètre est transmis dans le EDIregistre, tandis que le kparamètre est transmis dans le ESIregistre. Comme pour toutes les conventions d'appel x86, le résultat est renvoyé dans le EAXregistre.

Pour appeler cela depuis C, vous le prototyperiez comme suit:

int Bounce(int x, int k);

Essayez-le en ligne!

Mnémoniques d'assemblage non golfés:

; 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

Notez que la première section (qui prend la valeur absolue) aurait pu être écrite de manière équivalente:

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

qui est exactement le même nombre d'octets (6). Les performances devraient être similaires, peut-être légèrement plus rapides (sauf sur certaines puces Intel, où les mouvements conditionnels sont lents ).

XCHGest, bien sûr, relativement lent et ne serait pas préféré à l' MOVexception du golf de code (que le premier est de 1 octet lorsque l'un des opérandes est l'accumulateur, alors qu'un registre-registre MOVest toujours de 2 octets).

Cody Grey
la source
6

Gelée , 3 octets

æ%A

Essayez-le en ligne!

Ftw intégré.

Explication

æ%est un utile intégré ici. Je ne sais pas comment le décrire, donc je vais juste fournir la sortie pour certaines entrées:

Comme xva de 0à l'infini, xæ%4va 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)où la partie entre parenthèses est répétée à l'infini dans les deux sens.

Leaky Nun
la source
3

Ruby, 40 octets 32 octets

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

Essayez-le en ligne!

Explication

Salut, c'est ma première réponse sur ce site! Ce code est basé sur l'observation que la fonction de rebond se comporte exactement comme modulo lorsque ( n -1) k <= x < nk et n est impair, et se comporte comme une opération modulo inversée lorsque n est pair. (x/k+1)est le plus petit entier supérieur à x / k (qui est x / k +1 arrondi à un entier). Par conséquent, (x/k+1)trouve le n mentionné ci-dessus. %2>0vérifie si n est impair ou pair. Si n mod 2> 0, alors n est impair. Si nmod 2 = 0, alors n est pair. Si n est impair, alors la fonction de rebond doit être égale à x mod k . Si n est pair, la fonction de rebond doit être l'inverse, égale à k - x mod k . L'expression entière (x/k+1)%2>0?x%k:k-x%ktrouve n , puis exécute le x mod k s'il est impair, et exécute k - x mod k sinon.

La réponse a été améliorée sur la base d'une suggestion de Cyoce .

CyborgOctopus
la source
Vous pouvez le convertir en lambda. Au lieu d' def b(x,k) ... endutilisation->x,k{...}
Cyoce
Et puisque vous avez affaire à des entiers, ce .to_in'est pas nécessaire.
Cyoce
2

Mathematica, 19 octets

Abs@Mod[#,2#2,-#2]&
alephalpha
la source
1

J, 25 octets

Allusion:

C'est juste un modulo régulier sur les numéros d'échelle. Par exemple, dans le cas de 5:0 1 2 3 4 5 4 3 2 1

Voici une solution (pas encore bien golfée) dans J. Essayera de s'améliorer demain:

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

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

compressé2: [((|~#){])(<:|.|@}.@i:)@]

Essayez-le en ligne!

Jonas
la source
Je sens que je i:peux l'utiliser ici, mais je n'ai pas encore essayé de solution
Conor O'Brien
@ ConorO'Brien consultez ma version compressée2, elle économise quelques octets en utilisant i:. Je n'ai tout simplement pas eu le temps de mettre à jour le principal et de fournir une explication. Je m'attends à ce qu'un expert puisse raser encore 4 ou 5 octets au moins ...
Jonah
((|~#){])]-|@}:@i:pour 18 octets
miles
@miles beautiful, tyvm
Jonah
1

QBIC , 25 30 27 octets

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

A fait un peu de restructuration ...

Explication

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
la source
QBIC fait-il quelque chose de différent pour les opérations MOD que les autres implémentations de base? Other Basics renvoie MOD avec le même signe que le dividende; qui échouerait à x-13 et à k14 ans.
Cody Gray
@CodyGray Non, il a donné -13. Fixé maintenant.
steenbergh
Vous n'avez pas besoin des absdeux fois?
Neil
@Neil avez-vous un test pour cela?
steenbergh
@Neil nvm, je l'ai corrigé en restructurant le tout.
steenbergh
1

C89, 40 octets

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

Port AC de ma réponse de code machine x86 , cela définit une fonction f, qui calcule le rebond-modulo pour les paramètres xet k.

Il utilise la règle implicit-int de C89, de sorte que les deux paramètres, la variable globale tet la valeur de retour de la fonction sont tous implicitement de type int. La variable globale test juste utilisée pour contenir une valeur temporaire, ce qui finit par économiser des octets, par rapport à la répétition du calcul de chaque côté de l'opérateur conditionnel.

La absfonction (valeur absolue) est fournie dans l'en- <stdlib.h>tête, mais nous n'avons pas à l'inclure ici, encore une fois grâce à la règle implicite-int de C89 (où la fonction est implicitement déclarée et supposée retourner int).

Essayez-le en ligne!

Version non golfée:

#include <stdlib.h>

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

En regardant cela à la lumière de mon code machine réglé à la main , les compilateurs génèrent en fait une assez bonne sortie pour cela. Je veux dire, ils devraient; c'est une fonction assez simple à optimiser! J'ai cependant découvert un bogue mineur dans l'optimiseur x86-64 de GCC , où il produit curieusement un code plus gros lorsque vous lui dites d'optimiser la taille et un code plus petit lorsque vous lui dites d'optimiser la vitesse .

Cody Grey
la source
m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}est plus court
user41805
Sauf qu'il ne retourne pas réellement une valeur, @cows, sauf dans certaines circonstances mal définies en raison d'une bizarrerie du générateur de code GCC sur des cibles x86. C'est un modèle que je vois que les gens utilisent ici, mais cela ne fonctionne pas pour moi, pas plus que de retirer des ordures aléatoires de la pile qui se trouve être la bonne réponse.
Cody Gray
1

Haskell, 37 octets

Essayez-le en ligne!

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

Comment utiliser:
Appelez comme 15#14pour les arguments gauches non négatifs et comme (-13)#14pour les arguments gauches négatifs, car Haskell interpréterait -13#14comme -(13#14)si vous utilisiez quelque chose comme ghci. Le lien TIO prend simplement deux arguments de ligne de commande.

Explication:
Redéfinit d'abord l'opérateur d'infixe binaire !pour qu'il soit identique à mod. Haskell affiche modtoujours une valeur non négative, nous n'avons donc pas besoin de ce absque font les autres solutions ici. Il vérifie ensuite si x/k(division entière) est impair et si c'est le cas, retourne k-x mod k(c'est-à-dire le back-bounce) ou bien il retourne x mod k.

SEJPM
la source
C'est probablement juste une question de goût, mais je préfère personnellement ne pas définir !car cela n'économise aucun octetx#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Mark S.
1

PHP, 40 50 octets

putain de dollars. putain de frais généraux d'importation. :)

version entière:

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

ou

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

version flottante, 56 octets:

Remplacez abs($x)%$kpar fmod(abs($x),$k).


modifier: résultats fixes pour négatif x

Titus
la source
4
"Putain de dollars". Ouais, l'argent pue ...
steenbergh
2
Que diriez-vous €argvou £argv? Celles-ci auraient fière allure: x
Ismael Miguel
1

JavaScript (ES6), 36 32 octets

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

Rebondit récursivement xcontre 0et k, tellement dans l'esprit du défi.

Neil
la source
0

Lisp commun, 41 octets

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

Essayez-le en ligne!

Renzo
la source
0

C (gcc), 43 53 octets

Modifier: correction d'un problème négatif

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

Essayez-le en ligne!

Coton Zachary
la source
2
Cela fournit la mauvaise réponse pour (-13, 14) (-13 au lieu de 13). Les opérations de module et de reste se comportent différemment sur des nombres négatifs.
CAD97
0

R, 28 octets

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

Qui évalue à la fonction:

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

Ce qui semble être la méthode utilisée par la plupart des solutions. Je ne les ai pas regardés avant de faire ça.

JAD
la source