Модуль відмов два числа


12

Графік операції по модулю ( ) виглядає так:y=xmodk

Графік модульної функції

Це дуже корисна функція, оскільки вона дозволяє нам створити "обгорткове" поведінку. Однак це дуже громіздко, коли я хочу використовувати його, щоб створити вигляд "підстрибування" між двома стінами. Графік функції "відмов" ( ) виглядає так:y=bounce(x,k)

Графік функції "відмов-модуль"

Період графіка є . Період графіка становить , оскільки він рухається вгору для одиниць, а потім рухається вниз для інших одиниць, перш ніж повернутися туди, де він почався. Для обох функцій мінімальне значення дорівнює 0, а максимальне - (Власне, для функції модуля з інтегральними входами це ). Крім того, для обох функцій значення, де дорівнює 0.k y = відскок ( x , k ) 2 k k k yy=xmodkky=bounce(x,k)2kkkyk - 1 x = 0kk1x=0

Змагання

Давши ціле число і додатне ціле число , поверніть ціле число або наближення з плаваючою комою .k y = відмов ( x , k )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 Whoops. Я маю на увазі результат.
Esolanging Fruit

1
На жаль, це я вже подумав. Це все-таки неправильно. k % k = 0
Пітер Тейлор

@PeterTaylor О, я розумію ваше запитання. Я спочатку розробляв це на увазі з плаваючою точкою, а потім перейшов на лише ints після. Відредагуємо.
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). Дотримуючись конвенції виклику System V AMD64, що використовується в системах 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

Спробуйте в Інтернеті!

Вбудовані ftw.

Пояснення

æ%тут корисна вбудована. Я не знаю, як це описати, тому я просто надам вихід для деяких входів:

Як xйде від 0нескінченності, xæ%4іде 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)там, де частина в дужках повторюється до нескінченності обома способами.




3

Ruby, 40 байт 32 байти

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

Спробуйте в Інтернеті!

Пояснення

Привіт, це моя перша відповідь на цьому сайті! Цей код заснований на спостереженні, що функція відмов поводиться точно так само, як модуль, коли ( n -1) k <= x < nk і n непарне, і поводиться як зворотна операція модуля, коли n парне. (x/k+1)- найменше ціле число, що перевищує x / k (яке x / k +1 округлене до цілого числа). Таким чином, (x/k+1)знаходить п згадано вище. %2>0перевіряє, чи n є непарним чи парним. Якщо n mod 2> 0, то n непарне. Якщо nmod 2 = 0, тоді n іншому випадку.рівномірний. Якщо n непарне, то функція відмов повинна дорівнювати 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

Відповідь було покращено на підставі пропозиції Кіоса .


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

А оскільки ви маєте справу з цілими числами, .to_iце не потрібно.
Кіос



1

J, 25 байт

Підказка:

Це просто звичайний модуль на номерах сходів. Наприклад, у випадку 5:0 1 2 3 4 5 4 3 2 1

Ось (ще не добре розігране) рішення Дж. Спробуємо покращити завтра:

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

стислий: [((|~#){])(i.@>:,}:@i.@-)@]

стислий2: [((|~#){])(<:|.|@}.@i:)@]

Спробуйте в Інтернеті!


Я відчуваю, що i:тут можна використовувати, але я ще не пробував рішення
Conor O'Brien

@ ConorO'Brien перевірити мою компресовану версію2, це економить кілька байтів, використовуючи i:. Просто не встигли оновити основний і дати пояснення. Я очікую, що експерт міг би поголити ще 4 або 5 байт ...
Йона

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

@miles beautiful, tyvm
Jonah

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, ніж інші базові реалізації? Інші основи повертають MOD з тим же знаком, що і дивіденд; це не вдасться, коли xце -13, а k14.
Коді Грей

@CodyGray Ні, це дало -13. Виправлено зараз.
steenbergh

Вам не потрібно absобидва рази?
Ніл

@Neil у вас є тест-скринька для цього?
steenbergh

@Neil nvm, я це виправив, реструктурувавши всю справу.
steenbergh

1

C89, 40 байт

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

AC-відповідь мого машинного коду x86 відповідає , це визначає функцію f, яка обчислює модуль відмов для параметрів 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;
}

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


m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}коротше
користувач41805

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

1

Хаскелл, 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 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];

float версія, 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.