Bouncing-modulo dua angka

12

Grafik operasi modulo ( ) terlihat seperti ini:y=xmodk

Grafik fungsi modulo

Ini adalah fungsi yang sangat berguna, karena memungkinkan kita untuk membuat perilaku "membungkus". Namun, itu sangat rumit ketika saya ingin menggunakannya untuk membuat tampilan "memantul" di antara dua dinding. Grafik fungsi "bouncing" ( y=bounce(x,k) ) terlihat seperti ini:

Grafik fungsi "bounce-modulo"

The periode dari grafik yaitu . Periode grafik adalah , karena bergerak ke atas untuk unit , dan kemudian bergerak ke bawah untuk unit lain , sebelum kembali ke tempat dimulainya. Untuk kedua fungsi, nilai minimum untuk adalah 0, dan maksimum adalah (Sebenarnya, untuk fungsi modulus dengan input integral, ). Selain itu, untuk kedua fungsi, nilai adalah 0.k y = bouncing ( x , k ) 2 k ky=xmodkky=bounce(x,k)2kky k k - 1 x = 0kykk1x=0

Tantangan

Dengan bilangan bulat dan bilangan bulat positif , kembalikan pendekatan bilangan bulat atau titik mengambang dari .k y = bouncing ( x , k )xky=bounce(x,k)

Ini adalah , sehingga pengiriman terpendek yang valid (dihitung dalam byte) menang.

Uji Kasus

  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

Bonus poin untuk Fourier berbasis pendekatan Fourier .

Buah Esolanging
sumber
" Untuk kedua fungsi, nilai minimum untuk x adalah 0, dan maksimum adalah k " benar-benar salah.
Peter Taylor
@PeterTaylor Whoops. Maksud saya hasilnya.
Buah Esolanging
1
Ups, itulah yang saya pikir sudah dikatakan. Itu masih salah. k % k = 0
Peter Taylor
@ PeterTaylor Oh, saya mengerti pertanyaan Anda. Saya awalnya merancang ini dengan floating-point dalam pikiran, kemudian beralih ke ints after. Akan diedit.
Buah Esolanging
1
@PeterTaylor Jika argumennya mengambang, maka maksimumnya adalah angka yang mendekati k.
Buah Esolanging

Jawaban:

7

x86-64 Kode Mesin, 18 byte

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

Kode ini mendefinisikan fungsi dalam bahasa mesin x86-64 yang menghitung bounce(x, k). Mengikuti konvensi pemanggilan Sistem V AMD64 yang digunakan pada sistem Gnu / Unix, xparameter dilewatkan dalam EDIregister, sementara kparameter dilewatkan dalam ESIregister. Seperti dengan semua konvensi pemanggilan x86, hasilnya dikembalikan dalam EAXregister.

Untuk memanggil ini dari C, Anda akan membuat prototipe sebagai berikut:

int Bounce(int x, int k);

Cobalah online!

Mnemonik perakitan tidak dikumpulkan:

; 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

Perhatikan bahwa bagian pertama (yang mengambil nilai absolut) dapat secara setara ditulis:

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

yang merupakan jumlah byte yang sama persis (6). Kinerja harus serupa, mungkin sedikit lebih cepat (kecuali pada chip Intel tertentu, di mana gerakan bersyarat lambat ).

XCHGtentu saja relatif lambat dan tidak akan disukai MOVkecuali dalam kode golf (bahwa yang pertama adalah 1-byte ketika salah satu operan adalah akumulator, sedangkan register-register MOVselalu 2 byte).

Cody Grey
sumber
6

Jelly , 3 byte

æ%A

Cobalah online!

Built-in ftw.

Penjelasan

æ%adalah built-in yang berguna di sini. Saya tidak tahu bagaimana menggambarkannya, jadi saya hanya akan memberikan output untuk beberapa input:

Sebagai xpergi dari 0tak terbatas, xæ%4pergi di 0,1,2,3,4,(-3,-2,-1,0,1,2,3,4,)mana bagian dalam kurung diulangi hingga tak terbatas kedua cara.

Biarawati Bocor
sumber
3

Ruby, 40 byte 32 byte

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

Cobalah online!

Penjelasan

Hai, ini jawaban pertama saya di situs ini! Kode ini didasarkan pada pengamatan bahwa fungsi bouncing berperilaku persis seperti modulo ketika ( n -1) k <= x < nk dan n ganjil, dan berperilaku seperti operasi modulo terbalik ketika n adalah genap. (x/k+1)adalah bilangan bulat terkecil yang lebih besar dari x / k (yaitu x / k +1 dibulatkan ke bilangan bulat). Oleh karena itu, (x/k+1)temukan n yang disebutkan di atas. %2>0memeriksa untuk melihat apakah n ganjil atau genap. Jika n mod 2> 0, maka n ganjil. Jika nmod 2 = 0, maka n adalah genap. Jika n ganjil, maka fungsi bouncing harus sama dengan x mod k . Jika n adalah genap, fungsi bouncing seharusnya terbalik, sama dengan k - x mod k . Seluruh ekspresi (x/k+1)%2>0?x%k:k-x%kmenemukan n , kemudian mengeksekusi x mod k jika itu aneh, dan mengeksekusi k - x mod k sebaliknya.

Jawabannya ditingkatkan berdasarkan saran dari Cyoce .

CyborgOctopus
sumber
Anda dapat mengonversikan ini menjadi lambda. Alih-alih def b(x,k) ... endmenggunakan->x,k{...}
Cyoce
Dan karena Anda berurusan dengan bilangan bulat, .to_itidak perlu.
Cyoce
2

Mathematica, 19 byte

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

J, 25 byte

Petunjuk:

Ini hanya modulo reguler pada nomor tangga. Misalnya, dalam kasus 5:0 1 2 3 4 5 4 3 2 1

Berikut adalah solusi (belum golf dengan baik) di J. Akan mencoba untuk meningkatkan besok:

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

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

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

Cobalah online!

Jonah
sumber
Saya merasa seperti i:dapat digunakan di sini, tetapi saya belum mencoba solusi
Conor O'Brien
@ ConorO'Brien periksa versi compressed2 saya, menghemat beberapa byte menggunakan i:. Hanya belum punya waktu untuk memperbarui yang utama dan memberikan penjelasan. Saya berharap seorang ahli bisa mencukur setidaknya 4 atau 5 byte lagi ...
Jonah
((|~#){])]-|@}:@i:untuk 18 byte
mil
@miles beautiful, tyvm
Jonah
1

QBIC , 25 30 27 byte

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

Melakukan sedikit restrukturisasi ...

Penjelasan

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
sumber
Apakah QBIC melakukan sesuatu yang berbeda untuk operasi MOD daripada implementasi Dasar lainnya? Dasar-dasar lainnya mengembalikan MOD dengan tanda yang sama dengan dividen; itu akan gagal ketika x-13 dan k14.
Cody Gray
@CodyGray Tidak, itu memberi -13. Diperbaiki sekarang
steenbergh
Apakah kamu tidak perlu abskedua kali?
Neil
@Neil Anda punya testcase untuk itu?
steenbergh
@Neil nvm, saya sudah memperbaikinya dengan merestrukturisasi semuanya.
steenbergh
1

C89, 40 byte

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

Port AC jawaban kode mesin x86 saya , ini mendefinisikan fungsi f,, yang menghitung bouncing-modulo untuk parameter xdan k.

Ia menggunakan aturan implisit-int C89, sehingga kedua parameter, variabel global t, dan nilai pengembalian fungsi semuanya secara implisit bertipe int. Variabel global thanya digunakan untuk menyimpan nilai sementara, yang akhirnya menghemat byte, dibandingkan dengan mengulangi perhitungan di kedua sisi operator bersyarat.

The absfunction (nilai absolut) disediakan di <stdlib.h>header, tapi kita tidak harus menyertakan di sini, lagi berkat aturan implisit int C89 (di mana fungsi ini secara implisit dinyatakan dan diasumsikan kembali int).

Cobalah online!

Versi tidak disatukan:

#include <stdlib.h>

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

Melihat ini mengingat kode mesin yang disetel dengan tangan saya , kompiler sebenarnya menghasilkan output yang cukup bagus untuk ini. Maksud saya, mereka harus; itu fungsi yang cukup sederhana untuk dioptimalkan! Saya menemukan bug kecil di pengoptimal x86-64 GCC , meskipun, di mana anehnya menghasilkan kode yang lebih besar ketika Anda mengatakannya untuk mengoptimalkan ukuran dan kode yang lebih kecil ketika Anda mengatakannya untuk mengoptimalkan kecepatan .

Cody Grey
sumber
m;f(x,k){m=abs(x%k);x=x/k%2?k-m:m;}lebih pendek
user41805
Kecuali bahwa itu tidak benar-benar mengembalikan nilai, @ sapi, selain dalam keadaan tidak jelas tertentu karena kekhasan generator kode GCC pada target x86. Ini adalah template yang saya lihat digunakan orang di sini, tetapi itu tidak berfungsi untuk saya, tidak lebih dari menarik sampah acak dari tumpukan yang kebetulan merupakan jawaban yang benar.
Cody Grey
1

Haskell, 37 Bytes

Cobalah online!

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

Cara menggunakan:
Panggil sebagai 15#14untuk argumen kiri non-negatif dan (-13)#14untuk argumen kiri negatif, karena Haskell akan menafsirkan -13#14seolah- -(13#14)olah Anda menggunakan sesuatu seperti ghci. TIO-link hanya membutuhkan dua argumen baris perintah.

Penjelasan:
Pertama mendefinisikan ulang operator infiks biner !menjadi sama dengan mod. Haskell modselalu menampilkan nilai non-negatif, jadi kita tidak memerlukan abssolusi lain di sini. Ini kemudian memeriksa apakah x/k(pembagian integer) aneh dan jika demikian, mengembalikan k-x mod k(yaitu kembali-bouncing) atau kembali x mod k.

SEJPM
sumber
Ini mungkin hanya masalah selera, tapi saya pribadi lebih suka tidak mendefinisikan !karena tidak menyimpan byte lebihx#k|odd$x`div`k=k-x`mod`k|1<2=x`mod`k
Mark S.
1

PHP, 40 50 byte

dolar sialan. sialan impor overhead. :)

versi integer:

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

atau

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

versi float, 56 byte:

Ganti abs($x)%$kdengan fmod(abs($x),$k).


sunting: hasil tetap untuk negatif x

Titus
sumber
4
"Dolar sialan". Ya, uang berbau ...
steenbergh
2
Bagaimana dengan €argvatau £argv? Itu akan terlihat bagus: x
Ismael Miguel
1

JavaScript (ES6), 36 32 byte

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

Bouncing secara rekursif xterhadap 0dan k, sangat banyak dalam semangat tantangan.

Neil
sumber
0

Gangguan Umum, 41 byte

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

Cobalah online!

Renzo
sumber
0

C (gcc), 43 53 byte

Sunting: Memperbaiki masalah negatif

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

Cobalah secara Online!

Zachary Cotton
sumber
2
Ini memberikan jawaban yang salah untuk (-13, 14) (-13 bukannya 13). Modulus dan operasi sisanya berperilaku berbeda pada bilangan negatif.
CAD97
0

R, 28 byte

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

Yang mengevaluasi fungsi:

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

Yang tampaknya menjadi metode yang paling banyak digunakan solusi. Saya tidak melihat mereka sebelum membuat ini.

JAD
sumber