Bounce-modulo due numeri


12

Il grafico dell'operazione modulo ( y=xmodk ) è simile al seguente:

Grafico della funzione modulo

Questa è una funzione molto utile, in quanto ci consente di creare un comportamento "avvolgente". Tuttavia, è molto ingombrante quando voglio usarlo per creare un aspetto di "rimbalzo" tra due pareti. Il grafico della funzione "rimbalzo" ( y=bounce(x,k) ) è simile al seguente:

Grafico della funzione "bounce-modulo"

Il periodo del grafico di è . Il periodo del grafico di è , perché si sposta verso l'alto per unità, quindi si sposta verso il basso per altre unità, prima di tornare al punto di partenza. Per entrambe le funzioni, il valore minimo per è 0 e il massimo è (in realtà, per la funzione del modulo con ingressi integrati, è ). Inoltre, per entrambe le funzioni, il valore in cui è 0.k y = rimbalzo ( x , k ) 2 k k k y k k - 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

La sfida

Dato un intero e un intero positivo , restituisce un'approssimazione di numeri interi o in virgola mobile di .k y = rimbalzo ( x , k )xky=bounce(x,k)

Questo è , quindi vince l'invio valido più breve (conteggiato in byte).

Casi 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

Punti bonus per un Fourier -based approccio Fourier .


" Per entrambe le funzioni, il valore minimo per x è 0 e il massimo è k " è semplicemente sbagliato.
Peter Taylor,

@PeterTaylor Whoops. Intendo il risultato.
Esolanging Fruit,

1
Oops, è quello che pensavo avesse già detto. È ancora sbagliato. k % k = 0
Peter Taylor,

@PeterTaylor Oh, capisco la tua domanda. Inizialmente l'avevo progettato pensando alla virgola mobile, poi sono passato a soli ints dopo. Modifica.
Esolanging Fruit,

1
@PeterTaylor Se gli argomenti sono float, il massimo è un numero arbitrariamente vicino k.
Esolanging Fruit,

Risposte:


7

x86-64 Codice macchina, 18 byte

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

Questo codice definisce una funzione nel linguaggio macchina x86-64 che calcola bounce(x, k). A seguito della convenzione di chiamata AMD64 di System V utilizzata sui sistemi Gnu / Unix, il xparametro viene passato nel EDIregistro, mentre il kparametro viene passato nel ESIregistro. Come per tutte le convenzioni di chiamata x86, il risultato viene restituito nel EAXregistro.

Per chiamare questo da C, lo prototipo come segue:

int Bounce(int x, int k);

Provalo online!

Mnemonici di assemblaggio non golfati:

; 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

Si noti che la prima sezione (che assume il valore assoluto) avrebbe potuto essere scritta in modo equivalente:

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

che è lo stesso numero esatto di byte (6). Le prestazioni dovrebbero essere simili, forse leggermente più veloci (ad eccezione di alcuni chip Intel, dove le mosse condizionate sono lente ).

XCHGè, ovviamente, relativamente lento e non sarebbe preferito MOVse non nel golf del codice (che il primo è 1 byte quando uno degli operandi è l'accumulatore, mentre un registro-registro MOVè sempre di 2 byte).


6

Gelatina , 3 byte

æ%A

Provalo online!

Ftw incorporato.

Spiegazione

æ%è un utile built-in qui. Non so come descriverlo, quindi fornirò solo l'output per alcuni input:

Come xva 0dall'infinito, xæ%4va 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)dove la parte tra parentesi si ripete all'infinito in entrambi i modi.




3

Rubino, 40 byte 32 byte

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

Provalo online!

Spiegazione

Ciao, questa è la mia prima risposta su questo sito! Questo codice si basa sull'osservazione che la funzione bounce si comporta esattamente come modulo quando ( n -1) k <= x < nk e n è dispari e si comporta come un'operazione di modulo invertita quando n è pari. (x/k+1)è il numero intero più piccolo maggiore di x / k (che è x / k +1 arrotondato per difetto a un numero intero). Pertanto, (x/k+1)trova la n di cui sopra. %2>0controlla se n è pari o dispari. Se n mod 2> 0, allora n è dispari. Se nmod 2 = 0, quindi n è pari. Se n è dispari, la funzione di rimbalzo dovrebbe essere uguale a x mod k . Se n è pari, la funzione di rimbalzo dovrebbe essere inversa, uguale a k - x mod k . L'intera espressione (x/k+1)%2>0?x%k:k-x%ktrova n , quindi esegue x mod k se è dispari ed esegue k - x mod k in caso contrario.

La risposta è stata migliorata sulla base di un suggerimento di Cyoce .


Puoi convertirlo in un lambda. Invece di def b(x,k) ... endusare->x,k{...}
Cyoce il

E poiché hai a che fare con numeri interi, .to_inon è necessario.
Cyoce,



1

J, 25 byte

Suggerimento:

Questo è solo un modulo normale sui numeri della scala. Ad esempio, nel caso di 5:0 1 2 3 4 5 4 3 2 1

Ecco una soluzione (non ancora ben giocata) in J. Proverò a migliorare domani:

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

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

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

Provalo online!


Sento che i:può essere usato qui, ma non ho ancora provato una soluzione
Conor O'Brien

@ ConorO'Brien controlla la mia versione compressa2, risparmia pochi byte usando i:. Non ho avuto il tempo di aggiornare quello principale e fornire una spiegazione. Mi aspetto che un esperto possa radere almeno altri 4 o 5 byte ...
Giona

((|~#){])]-|@}:@i:per 18 byte
miglia

@miles beautiful, tyvm
Jonah,

1

QBIC , 25 30 27 byte

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

Ha fatto un po 'di ristrutturazione ...

Spiegazione

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

QBIC fa qualcosa di diverso per le operazioni MOD rispetto ad altre implementazioni di base? Altre nozioni di base restituiscono MOD con lo stesso segno del dividendo; ciò fallirebbe quando xè -13 ed kè 14.
Cody Gray il

@CodyGray No, ha dato -13. Riparato ora.
Steenbergh,

Non hai bisogno di absentrambe le volte?
Neil,

@Neil hai una testcase per quello?
Steenbergh,

@Neil nvm, l'ho risolto ristrutturando il tutto.
Steenbergh,

1

C89, 40 byte

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

Porta AC della mia risposta del codice macchina x86 , definisce una funzione f, che calcola il modulo di rimbalzo per i parametri xe k.

Usa la regola implicita-int di C89, quindi entrambi i parametri, la variabile globale te il valore di ritorno della funzione sono tutti implicitamente di tipo int. La variabile globale tviene utilizzata solo per contenere un valore temporaneo, che finisce per salvare byte, rispetto alla ripetizione del calcolo su entrambi i lati dell'operatore condizionale.

La absfunzione (valore assoluto) è fornita <stdlib.h>nell'intestazione, ma non è necessario includerla qui, sempre grazie alla regola implicita-int di C89 (dove la funzione è implicitamente dichiarata e si presume che ritorni int).

Provalo online!

Versione non golfata:

#include <stdlib.h>

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

Guardando questo alla luce del mio codice macchina sintonizzato a mano , i compilatori in realtà generano un output abbastanza buono per questo. Voglio dire, dovrebbero; è una funzione abbastanza semplice da ottimizzare! Ho scoperto un bug minore nell'ottimizzatore x86-64 di GCC , tuttavia, dove curiosamente produce codice più grande quando gli dici di ottimizzare per dimensioni e codice più piccolo quando gli dici di ottimizzare per velocità .


m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}è più corto
user41805

Solo che in realtà non restituisce un valore, @cows, se non in determinate circostanze mal definite a causa di una stranezza del generatore di codice GCC su target x86. È un modello che vedo le persone usano qui, ma non funziona per me, non più che estrarre spazzatura casuale dallo stack che sembra essere la risposta corretta.
Cody Gray,

1

Haskell, 37 byte

Provalo online!

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

Come usare:
Chiama come 15#14per gli argomenti di sinistra non negativi e come (-13)#14per gli argomenti di sinistra negativi, perché Haskell interpreterebbe -13#14come -(13#14)se stessi usando qualcosa di simile ghci. Il collegamento TIO accetta semplicemente due argomenti della riga di comando.

Spiegazione: Per
prima cosa ridefinisce l'operatore binario infix !in modo che sia uguale a mod. Haskell modproduce sempre un valore non negativo, quindi non abbiamo bisogno delle absaltre soluzioni qui. Quindi controlla se x/k(divisione intera) è dispari e, in tal caso, restituisce k-x mod k(ovvero il back-bounce) oppure restituisce x mod k.


Probabilmente è solo una questione di gusti, ma personalmente preferisco non definire !poiché non salva alcun byte oltrex#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Mark S.

1

PHP, 40 50 byte

dannati dollari. dannatamente importazione ambientale. :)

versione intera:

[,$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];

versione float, 56 byte:

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


modifica: risultati fissi per negativi x


4
"Dannati dollari". Sì, il denaro puzza ...
steenbergh,

2
Che ne dici di €argvo £argv? Sarebbero belli: x
Ismael Miguel,

1

JavaScript (ES6), 36 32 byte

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

Rimbalza ricorsivamente xcontro 0e k, nello spirito della sfida.



0

C (gcc), 43 53 byte

Modifica: risolto problema negativo

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

Provalo online!


2
Ciò fornisce la risposta errata per (-13, 14) (-13 invece di 13). Le operazioni del modulo e del resto si comportano diversamente su numeri negativi.
CAD97,

0

R, 28 byte

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

Che valuta la funzione:

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

Quale sembra essere il metodo utilizzato dalla maggior parte delle soluzioni. Non li ho guardati prima di farlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.