Módulo de rejeição dois números

12

O gráfico da operação do módulo ( y=xmodk ) fica assim:

Gráfico da função módulo

Essa é uma função muito útil, pois permite criar um comportamento de "quebra automática". No entanto, é muito complicado quando eu quero usá-lo para criar uma aparência de "saltar" entre duas paredes. O gráfico da função "rejeição" ( y=bounce(x,k) ) tem a seguinte aparência:

Gráfico da função "módulo de rejeição"

O período do gráfico de é . O período do gráfico de é , porque se move para cima por unidades e depois se move para baixo por outras unidades, antes de retornar ao local onde foi iniciado. Para ambas as funções, o valor mínimo para é 0 e o máximo é (na verdade, para a função de módulo com entradas integrais, é ). Além disso, para ambas as funções, o valor em que é 0.k y = ressalto ( x , k ) 2 k k k y k k - 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

O desafio

Dado um número inteiro e um número inteiro positivo , retorne uma aproximação de número inteiro ou de ponto flutuante de .k y = salto ( x , k )xky=bounce(x,k)

Isso é , portanto, o menor envio válido (contado em bytes) vence.

Casos de teste

  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

Os pontos de bónus para um Fourier baseados abordagem em Fourier .

Esolanging Fruit
fonte
" Para ambas as funções, o valor mínimo para x é 0 e o máximo é k " está completamente errado.
Peter Taylor
@PeterTaylor Whoops. Eu quero dizer o resultado.
Esolanging Fruit
1
Opa, foi o que eu pensei que já havia dito. Ainda está errado. k % k = 0
Peter Taylor
@ Peter Taylor Oh, eu entendo sua pergunta. Eu tinha originalmente projetado isso com ponto flutuante em mente, depois mudado para apenas ints depois. Irá editar.
Esolanging Fruit
1
@PeterTaylor Se os argumentos forem flutuantes, o máximo é um número arbitrariamente próximo a k.
Esolanging Fruit

Respostas:

7

Código da 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 uma função na linguagem de máquina x86-64 que calcula bounce(x, k). Após a convenção de chamada System64 AMD64 usada nos sistemas Gnu / Unix, o xparâmetro é passado no EDIregistro, enquanto o kparâmetro é passado no ESIregistro. Como em todas as convenções de chamada x86, o resultado é retornado no EAXregistro.

Para chamar isso de C, você deve fazer o protótipo da seguinte maneira:

int Bounce(int x, int k);

Experimente online!

Mnemônicos de montagem não destruídos:

; 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

Observe que a primeira seção (que leva o valor absoluto) poderia ter sido escrita de forma equivalente:

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

que é exatamente o mesmo número de bytes (6). O desempenho deve ser semelhante, talvez um pouco mais rápido (exceto em determinados chips da Intel, onde os movimentos condicionais são lentos ).

XCHGé, é claro, relativamente lento e não seria preferido, MOVexceto no código de golfe (que o primeiro tem 1 byte quando um dos operandos é o acumulador, enquanto um registrador MOVé sempre de 2 bytes).

Cody Gray
fonte
6

Geléia , 3 bytes

æ%A

Experimente online!

Ftw interno.

Explicação

æ%é um útil embutido aqui. Não sei como descrevê-lo, então fornecerei a saída para algumas entradas:

Como xvai do 0infinito, xæ%4vai para 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)onde a parte entre parênteses é repetida até o infinito nos dois sentidos.

Freira Furada
fonte
3

Ruby, 40 bytes 32 bytes

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

Experimente online!

Explicação

Olá, esta é a minha primeira resposta neste site! Esse código é baseado na observação de que a função de rejeição se comporta exatamente como o módulo quando ( n -1) k <= x < nk e n é ímpar e se comporta como uma operação de módulo invertido quando n é par. (x/k+1)é o menor número inteiro maior que x / k (que é x / k +1 arredondado para um número inteiro). Portanto, (x/k+1)encontra o n mencionado acima. %2>0verifica se n é ímpar ou par. Se n mod 2> 0, então n é ímpar. Se nmod 2 = 0, então n é par. Se n for ímpar, a função de rejeição deve ser igual a x mod k . Se n for par, a função de rejeição deve ser o inverso, igual a k - x mod k . A expressão inteira (x/k+1)%2>0?x%k:k-x%kencontra n , depois executa x mod k, se for ímpar, e executa k - x mod k, caso contrário.

A resposta foi aprimorada com base em uma sugestão da Cyoce .

CyborgOctopus
fonte
Você pode converter isso em um lambda. Em vez de def b(x,k) ... endusar->x,k{...}
Cyoce
E como você está lidando com números inteiros, .to_inão é necessário.
21918 Cyoce
2

Mathematica, 19 bytes

Abs@Mod[#,2#2,-#2]&
alefalpha
fonte
1

J, 25 bytes

Dica:

Este é apenas um módulo regular nos números da escada. Por exemplo, no caso de 5:0 1 2 3 4 5 4 3 2 1

Aqui está uma solução (ainda não bem-desenvolvida) em J. Tentará melhorar amanhã:

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

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

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

Experimente online!

Jonah
fonte
Eu sinto que i:pode ser usado aqui, mas ainda não tentei uma solução #
Conor O'Brien
@ ConorO'Brien confira minha versão do compact2, ele economiza alguns bytes usando i:. Só não tive tempo de atualizar o principal e fornecer uma explicação. Espero que um especialista poderia raspar mais 4 ou 5 bytes, pelo menos ...
Jonah
((|~#){])]-|@}:@i:para 18 bytes
milhas
@miles beautiful, tyvm
Jonah
1

QBIC , 25 30 27 bytes

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

Fiz um pouco de reestruturação ...

Explicação

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
fonte
O QBIC faz algo diferente para operações MOD do que outras implementações básicas? Outros princípios retornam MOD com o mesmo sinal que o dividendo; que falharia quando x-13 e k14.
Cody Gray
@CodyGray Não, deu -13. Corrigido agora.
21417 rj #
Você não precisa das absduas vezes?
Neil
@ Neil você tem um testcase para isso?
18717 joules:
@ Neil NVM, eu corrigi-lo através da reestruturação da coisa toda.
21417 rj #
1

C89, 40 bytes

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

A porta CA da resposta do meu código de máquina x86 define uma função fque calcula o módulo de rejeição para os parâmetros xe k.

Ele usa a regra implit-int do C89, para que ambos os parâmetros, a variável global te o valor de retorno da função sejam implicitamente do tipo int. A variável global té usada apenas para armazenar um valor temporário, que acaba salvando bytes, em comparação com a repetição da computação nos dois lados do operador condicional.

A absfunção (valor absoluto) é fornecida no <stdlib.h>cabeçalho, mas não precisamos incluí-la aqui, novamente graças à regra implit-int do C89 (onde a função é implicitamente declarada e supõe-se que retorne int).

Experimente online!

Versão não destruída:

#include <stdlib.h>

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

Olhando isso à luz do meu código de máquina ajustado à mão , os compiladores realmente geram uma saída muito boa para isso. Quero dizer, eles deveriam; é uma função bastante simples de otimizar! No entanto, eu descobri um pequeno bug no otimizador x86-64 do GCC , onde, curiosamente, produz código maior quando você pede para otimizar o tamanho e código menor quando você pede para otimizar a velocidade .

Cody Gray
fonte
m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}é menor
user41805
Exceto que, na verdade, ele não retorna um valor, @cows, exceto em determinadas circunstâncias mal definidas devido a uma peculiaridade do gerador de código GCC nos destinos x86. É um modelo que vejo as pessoas usarem aqui, mas não funciona para mim, assim como extrair lixo aleatório da pilha, que por acaso é a resposta correta.
Cody Grey
1

Haskell, 37 bytes

Experimente online!

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

Como usar:
Ligue 15#14para argumentos à esquerda não negativos e (-13)#14para argumentos à esquerda negativos, porque Haskell interpretaria -13#14como -(13#14)se você estivesse usando algo parecido ghci. O link TIO simplesmente aceita dois argumentos de linha de comando.

Explicação:
Primeiro redefine o operador de infixo binário !para ser o mesmo que mod. A Haskell modsempre gera um valor não negativo, portanto não precisamos das absoutras soluções aqui. Em seguida, verifica se x/k(divisão inteira) é ímpar e, em caso afirmativo, retorna k-x mod k(ou seja, o retorno) ou então retorna x mod k.

SEJPM
fonte
Este é provavelmente apenas uma questão de gosto, mas eu, pessoalmente, prefiro não definir !, uma vez que não salva nenhum bytes maisx#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 importação. :)

versão inteira:

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

versão flutuante, 56 bytes:

Substitua abs($x)%$kpor fmod(abs($x),$k).


editar: resultados fixos para negativos x

Titus
fonte
4
"Malditos dólares". Sim, o dinheiro cheira mal ...
steenbergh:
2
Que tal €argvou £argv? Isso seria bom: x
Ismael Miguel
1

JavaScript (ES6), 36 32 bytes

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

Bate xcontra recursivamente 0e k, muito no espírito do desafio.

Neil
fonte
0

Lisp comum, 41 bytes

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

Experimente online!

Renzo
fonte
0

C (gcc), 43 53 bytes

Editar: problema negativo corrigido

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

Experimente Online!

Zachary Cotton
fonte
2
Isso fornece a resposta errada para (-13, 14) (-13 em vez de 13). As operações de módulo e restante se comportam de maneira diferente em números negativos.
CAD97
0

R, 28 bytes

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

Que avalia a função:

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

Qual parece ser o método usado pela maioria das soluções. Eu não olhei para eles antes de fazer isso.

JAD
fonte