Отскок-по модулю два числа


12

График операции по модулю ( y=xmodk ) выглядит следующим образом:

График функции по модулю

Это очень полезная функция, так как она позволяет нам создавать поведение «обтекания». Тем не менее, это очень громоздко, когда я хочу использовать его, чтобы создать видимость "подпрыгивания" между двумя стенами. График функции "bounce" ( y=bounce(x,k) ) выглядит следующим образом:

График функции "bounce-modulo"

Период графика есть . Период графика равен , потому что он перемещается вверх на единиц, а затем движется вниз на другие единиц, прежде чем вернуться к тому, с чего начал. Для обеих функций минимальное значение для равно 0, а максимальное равно (на самом деле для функции модуля со встроенными входами это ). Кроме того, для обеих функций значение равно 0.k y = отскок ( x , k ) 2 k k k y k k - 1 x = 0y=xmodkky=bounce(x,k)2kkkykk1x=0

Соревнование

Если задано целое число и положительное целое число , вернуть целочисленное значение или приближение с плавающей запятой для .к у = отказов ( х , к )xky=bounce(x,k)

Это , поэтому выигрывает самая короткая действительная заявка (в байтах).

Тестовые случаи

  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

Бонусные баллы для Фурье -На подход Фурье .


« Для обеих функций минимальное значение x равно 0, а максимальное - k » просто неправильно.
Питер Тейлор

@PeterTaylor Ой. Я имею в виду результат.
Esolanging Fruit

1
Ой, это то, что я думал, что уже сказано. Это все еще неправильно. k % k = 0
Питер Тейлор

@PeterTaylor О, я понимаю твой вопрос. Первоначально я разработал это с учетом плавающей запятой, а затем переключился на целые числа. Буду редактировать.
Esolanging Fruit

1
@PeterTaylor Если аргументы являются числами с плавающей точкой, то максимум - это число, произвольно близкое к k.
Esolanging Fruit

Ответы:


7

Машинный код x86-64, 18 байт

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

Этот код определяет функцию на машинном языке x86-64, которая вычисляет bounce(x, k). В соответствии с соглашением о вызовах AMD64 в System V, используемым в системах Gnu / Unix, xпараметр передается в EDIрегистр, а kпараметр передается в ESIрегистр. Как и во всех соглашениях о вызовах x86, результат возвращается в EAXрегистр.

Чтобы вызвать это из C, вы должны создать его следующим образом:

int Bounce(int x, int k);

Попробуйте онлайн!

Неуправляемая сборка мнемоники:

; 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

Обратите внимание, что первый раздел (который принимает абсолютное значение) может быть эквивалентно написан:

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

что такое же количество байтов (6). Производительность должна быть схожей, возможно, немного быстрее (за исключением некоторых чипов Intel, где условные перемещения медленные )

XCHGэто, конечно, относительно медленно и не будет предпочтительнее, MOVкроме как в кодовом гольфе (то, что первый является 1-байтовым, когда один из операндов является аккумулятором, тогда как регистр-регистр MOVвсегда равен 2 байта).


6

Желе , 3 байта

æ%A

Попробуйте онлайн!

Встроенные модули

объяснение

æ%полезный встроенный здесь. Я не знаю, как это описать, поэтому я просто предоставлю вывод для некоторых входных данных:

Как xидет от 0бесконечности, xæ%4идет 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)туда , где часть в скобках повторяется до бесконечности в обоих направлениях.




3

Рубин, 40 байтов 32 байта

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

Попробуйте онлайн!

объяснение

Привет, это мой первый ответ на этом сайте! Этот код основан на наблюдении, что функция bounce ведет себя точно так же, как по модулю, когда ( n -1) k <= x < nk, и n нечетно, и ведет себя как обратная операция по модулю, когда n четно. (x/k+1)Наименьшее целое число больше, чем х / к (то есть х / к + 1, округленное до целого числа). Таким образом, (x/k+1)находит п упомянуто выше. %2>0проверяет, является ли n нечетным или четным. Если n mod 2> 0, то n нечетно. Если нmod 2 = 0, тогда n чётно. Если n нечетно, то функция bounce должна быть равна x mod k . Если n четное, функция отскока должна быть обратной, равной k - x mod k . Целое выражение (x/k+1)%2>0?x%k:k-x%kнаходит n , затем выполняет x mod k, если оно нечетное, и в противном случае выполняет k - x mod k .

Ответ был улучшен на основе предложения от Cyoce .


Вы можете преобразовать это в лямбду. Вместо def b(x,k) ... endиспользования->x,k{...}
Cyoce

И поскольку вы имеете дело с целыми числами, в .to_iэтом нет необходимости.
Cyoce



1

J, 25 байт

Подсказка:

Это просто по модулю на лестничные номера. Например, в случае 5:0 1 2 3 4 5 4 3 2 1

Вот (еще не удачное решение) в J. Попробую улучшить завтра:

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

сжато: [((|~#){])(i.@>:,}:@i.@-)@]

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

Попробуйте онлайн!


Я чувствую, что i:можно использовать здесь, но я еще не попробовал решение
Конор О'Брайен

@ ConorO'Brien посмотрите мою сжатую версию 2, она сэкономит несколько байт при использовании i:. Просто не успел обновить основной и дать объяснение. Я ожидаю, что эксперт сможет сбрить еще 4 или 5 байтов как минимум ...
Иона

((|~#){])]-|@}:@i:за 18 байт
миль

@ красивые миль, tyvm
Иона

1

QBIC , 25 30 27 байтов

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

Сделал немного реструктуризации ...

объяснение

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 что-то другое для операций MOD, чем другие реализации Basic? Другие основы возвращают MOD с тем же знаком, что и дивиденды; это потерпит неудачу, когда x-13 и k14.
Коди Грей

@CodyGray Нет, это дало -13. Исправлено сейчас.
Стинберг

Тебе не нужно absоба раза?
Нил

@ Нейл, у тебя есть тестовый сценарий для этого?
Стинберг

@ Нил НВМ, я исправил это, реструктурировав все это.
Стинберг

1

C89, 40 байт

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

AC-порт моего машинного кода ответа x86 , это определяет функцию f, которая вычисляет bounce-modulo для параметров xи k.

Он использует правило неявного-int C89, так что оба параметра, глобальная переменная tи возвращаемое значение функции неявно имеют тип int. Глобальная переменная tпросто используется для хранения временного значения, которое в конечном итоге сохраняет байты, по сравнению с повторением вычислений по обе стороны от условного оператора.

absФункция (абсолютное значение) обеспечивается в <stdlib.h>заголовке, но мы не должны включить его здесь, опять - таки благодаря неявной-ИНТ правило C89 (где функция неявно объявлена и предполагается возвращение int).

Попробуйте онлайн!

Безголовая версия:

#include <stdlib.h>

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

Глядя на это в свете моего вручную настроенного машинного кода , компиляторы на самом деле генерируют довольно хороший результат для этого. Я имею в виду, они должны; это довольно простая функция для оптимизации! Однако я обнаружил небольшую ошибку в оптимизаторе GCC x86-64 , когда он с любопытством создает код большего размера, когда вы говорите ему оптимизировать код по размеру, и код меньшего размера, когда вы говорите ему оптимизировать скорость .


m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}Короче
user41805

За исключением того, что он на самом деле не возвращает значение @cows, кроме как при определенных плохо определенных обстоятельствах из-за причуды генератора кода GCC для целей x86. Я вижу, что это шаблон, который люди используют здесь, но он не работает для меня, так же как и удаление случайного мусора из стека, который, как оказалось, является правильным ответом.
Коди Грей

1

Haskell, 37 байт

Попробуйте онлайн!

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

Как использовать:
Вызовите как 15#14для неотрицательных левых аргументов, так и (-13)#14для отрицательных левых аргументов, потому что Haskell будет интерпретировать, -13#14как -(13#14)будто вы используете что-то подобное ghci. TIO-ссылка просто принимает два аргумента командной строки.

Объяснение:
Сначала переопределяем двоичный инфиксный оператор, !чтобы он был таким же, как mod. Haskell's modвсегда выдает неотрицательное значение, поэтому нам не нужно то, absчто здесь делают другие решения. Затем он проверяет, является ли x/k(целочисленное деление) нечетным, и если да, возвращает k-x mod k(то есть обратный отскок) или же возвращает x mod k.


Это, вероятно, просто вопрос вкуса, но я лично предпочитаю не определять, !так как это не экономит больше байтовx#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Марк С.

1

PHP, 40 50 байт

чертовы доллары чертовски импортные накладные расходы. :)

целочисленная версия:

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

или

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

версия с плавающей запятой, 56 байт:

Заменить abs($x)%$kна fmod(abs($x),$k).


редактировать: исправлены отрицательные результаты x


4
"Чертовы доллары". Да, деньги
воняют

2
Как насчет €argvили £argv? Это выглядело бы неплохо: x
Исмаэль Мигель

1

JavaScript (ES6), 36 32 байта

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

Рекурсивно отскакивает xот 0и k, очень сильно, в духе задачи.



0

C (gcc), 43 53 байта

Изменить: Исправлена ​​отрицательная проблема

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

Попробуйте онлайн!


2
Это дает неправильный ответ для (-13, 14) (-13 вместо 13). Операции модуля и остатка ведут себя по-разному на отрицательных числах.
CAD97

0

R, 28 байт

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

Который оценивает функцию:

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

Который, кажется, метод, который использует большинство решений. Я не смотрел на них, прежде чем сделать это.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.