Módulo de rebote dos números

12

El gráfico de la operación de módulo ( y=xmodk ) se ve así:

Gráfico de la función de módulo

Esta es una función muy útil, ya que nos permite crear un comportamiento de "ajuste". Sin embargo, es muy engorroso cuando quiero usarlo para crear una apariencia de "rebote" entre dos paredes. El gráfico de la función "rebote" ( y=bounce(x,k) ) se ve así:

Gráfico de la función "módulo de rebote"

El período de la gráfica de es . El período de la gráfica de es , porque se mueve hacia arriba para unidades, y luego se mueve hacia abajo para otras unidades, antes de regresar a donde comenzó. Para ambas funciones, el valor mínimo para es 0, y el máximo es (en realidad, para la función de módulo con entradas integrales, es ). Además, para ambas funciones, el valor donde es 0.k y = rebote ( x , k ) 2 k k k y k k - 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

El reto

Dado un entero un entero positivo , devuelve una aproximación entera o de coma flotante de .k y = rebote ( x , k )xky=bounce(x,k)

Este es el , por lo que gana el envío válido más corto (contado en bytes).

Casos de prueba

  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

Los puntos de bonificación para un Fourier basados en el enfoque de Fourier .

Fruta Esolanging
fuente
" Para ambas funciones, el valor mínimo para x es 0, y el máximo es k " es simplemente incorrecto.
Peter Taylor
@PeterTaylor Whoops. Me refiero al resultado.
Esolanging Fruit
1
Vaya, eso es lo que pensé que ya decía. Aún está mal. k % k = 0
Peter Taylor
@PeterTaylor Oh, entiendo tu pregunta. Originalmente había diseñado esto con punto flotante en mente, luego cambié a solo ints después. Se editará
Esolanging Fruit
1
@PeterTaylor Si los argumentos son flotantes, entonces el máximo es un número arbitrariamente cercano a k.
Esolanging Fruit

Respuestas:

7

Código de máquina x86-64, 18 bytes

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

Este código define una función en lenguaje de máquina x86-64 que computa bounce(x, k). Siguiendo la convención de llamada System V AMD64 utilizada en los sistemas Gnu / Unix, el xparámetro se pasa en el EDIregistro, mientras que el kparámetro se pasa en el ESIregistro. Como con todas las convenciones de llamadas x86, el resultado se devuelve en el EAXregistro.

Para llamar a esto desde C, debería crear un prototipo de la siguiente manera:

int Bounce(int x, int k);

Pruébalo en línea!

Mnemónicos de ensamblaje sin golf:

; 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

Tenga en cuenta que la primera sección (que toma el valor absoluto) podría haberse escrito de manera equivalente:

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

que es exactamente el mismo número de bytes (6). El rendimiento debería ser similar, quizás un poco más rápido (excepto en ciertos chips Intel, donde los movimientos condicionales son lentos ).

XCHGes, por supuesto, relativamente lento y no se preferiría más que MOVen golf de código (que el primero es de 1 byte cuando uno de los operandos es el acumulador, mientras que un registro-registro MOVsiempre es de 2 bytes).

Cody Gray
fuente
6

Jalea , 3 bytes

æ%A

Pruébalo en línea!

Incorporado ftw.

Explicación

æ%es un útil incorporado aquí. No sé cómo describirlo, así que solo proporcionaré la salida para algunas entradas:

A medida que xva del 0infinito, xæ%4va 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)donde la parte entre paréntesis se repite al infinito en ambos sentidos.

Monja permeable
fuente
3

Rubí, 40 bytes 32 bytes

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

Pruébalo en línea!

Explicación

Hola, esta es mi primera respuesta en este sitio. Este código se basa en la observación de que la función de rebote se comporta exactamente como un módulo cuando ( n -1) k <= x < nk yn es impar, y se comporta como una operación de módulo inverso cuando n es par. (x/k+1)es el entero más pequeño mayor que x / k (que es x / k +1 redondeado a un entero). Por lo tanto, (x/k+1)encuentra la n mencionada anteriormente. %2>0comprueba si n es par o impar. Si n mod 2> 0, entonces n es impar. Si nmod 2 = 0, entonces n es par. Si n es impar, entonces la función de rebote debería ser igual a x mod k . Si n es par, la función de rebote debe ser inversa, igual a k - x mod k . La expresión completa (x/k+1)%2>0?x%k:k-x%kencuentra n , luego ejecuta x mod k si es impar, y ejecuta k - x mod k de lo contrario.

La respuesta fue mejorada en base a una sugerencia de Cyoce .

CyborgOctopus
fuente
Puedes convertir esto en una lambda. En lugar de def b(x,k) ... endusar->x,k{...}
Cyoce
Y como se trata de enteros, .to_ino es necesario.
Cyoce
2

Mathematica, 19 bytes

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

J, 25 bytes

Insinuación:

Esto es solo un módulo regular en los números de escalera. Por ejemplo, en el caso de 5:0 1 2 3 4 5 4 3 2 1

Aquí hay una solución (aún no bien desarrollada) en J. Intentará mejorar mañana:

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

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

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

Pruébalo en línea!

Jonás
fuente
Siento que i:se puede usar aquí, pero aún no he probado una solución
Conor O'Brien
@ ConorO'Brien echa un vistazo a mi versión comprimida2, ahorra unos pocos bytes usando i:. Simplemente no he tenido tiempo de actualizar el principal y proporcionar una explicación. Espero que un experto pueda reducir otros 4 o 5 bytes al menos ...
Jonah
((|~#){])]-|@}:@i:para 18 bytes
millas
@miles beautiful, tyvm
Jonah
1

QBIC , 25 30 27 bytes

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

Hice un poco de reestructuración ...

Explicación

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
fuente
¿QBIC hace algo diferente para las operaciones MOD que otras implementaciones básicas? Otros conceptos básicos devuelven MOD con el mismo signo que el dividendo; eso fallaría cuando xsea ​​-13 y ksea ​​14.
Cody Gray
@CodyGray No, dio -13. Corregido ahora.
steenbergh
¿No necesitas las absdos veces?
Neil
@Neil, ¿tienes un caso de prueba para eso?
steenbergh
@Neil nvm, lo arreglé reestructurando todo.
steenbergh
1

C89, 40 bytes

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

El puerto de CA de mi respuesta de código de máquina x86 , esto define una función f, que calcula el módulo de rebote para los parámetros xy k.

Utiliza la regla implícita-int de C89, de modo que ambos parámetros, la variable global ty el valor de retorno de la función son implícitamente de tipo int. La variable global tsolo se usa para mantener un valor temporal, que termina guardando bytes, en comparación con la repetición del cálculo a ambos lados del operador condicional.

La absfunción (valor absoluto) se proporciona en el <stdlib.h>encabezado, pero no tenemos que incluirla aquí, nuevamente gracias a la regla implícita-int de C89 (donde la función se declara implícitamente y se supone que regresa int).

Pruébalo en línea!

Versión sin golf:

#include <stdlib.h>

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

Mirando esto a la luz de mi código de máquina sintonizado a mano , los compiladores en realidad generan una salida bastante buena para esto. Quiero decir, deberían; ¡Es una función bastante simple de optimizar! Sin embargo, descubrí un error menor en el optimizador x86-64 de GCC , donde curiosamente produce un código más grande cuando le dice que optimice el tamaño y un código más pequeño cuando le dice que optimice la velocidad .

Cody Gray
fuente
m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}es más corto
user41805
Excepto que en realidad no devuelve un valor, @cows, excepto en ciertas circunstancias mal definidas debido a una peculiaridad del generador de código GCC en objetivos x86. Es una plantilla que veo que la gente usa aquí, pero no funciona para mí, más que sacar basura aleatoria de la pila que resulta ser la respuesta correcta.
Cody Gray
1

Haskell, 37 Bytes

Pruébalo en línea!

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

Cómo usarlo:
llama 15#14a los argumentos izquierdos no negativos y (-13)#14a los argumentos izquierdos negativos, porque Haskell interpretaría -13#14como -(13#14)si estuvieras usando algo así ghci. El enlace TIO simplemente toma dos argumentos de línea de comandos.

Explicación:
Primero redefine el operador infijo binario !para que sea el mismo que mod. Haskell modsiempre genera un valor no negativo, por lo que no necesitamos las absotras soluciones que aquí necesitamos . Luego comprueba si x/k(división entera) es impar y, de ser así, regresa k-x mod k(es decir, el rebote) o si no regresa x mod k.

SEJPM
fuente
Esto es probablemente solo una cuestión de gustos, pero personalmente prefiero no definirlo !ya que no guarda ningún bytex#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Mark S.
1

PHP, 40 50 bytes

malditos dólares. maldita sobrecarga de importación. :)

versión entera:

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

o

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

versión flotante, 56 bytes:

Reemplazar abs($x)%$kcon fmod(abs($x),$k).


editar: resultados fijos para negativo x

Titus
fuente
44
"Malditos dólares". Sí, el dinero apesta ...
steenbergh
2
¿Qué tal €argvo £argv? Esos se verían bien: x
Ismael Miguel
1

JavaScript (ES6), 36 32 bytes

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

Rebota de forma recursiva xcontra 0y k, por lo mucho en el espíritu del desafío.

Neil
fuente
0

C (gcc), 43 53 bytes

Editar: problema negativo corregido

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

Pruébalo en línea!

Algodón Zachary
fuente
2
Esto proporciona la respuesta incorrecta para (-13, 14) (-13 en lugar de 13). Las operaciones de módulo y resto se comportan de manera diferente en números negativos.
CAD97
0

R, 28 bytes

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

Lo que evalúa la función:

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

Cuál parece ser el método que utilizan la mayoría de las soluciones. No los miré antes de hacer esto.

JAD
fuente