Hitung checksum Adler-32


32

Latar Belakang

Adler-32 adalah checksum 32-bit yang ditemukan oleh Mark Adler pada tahun 1995 yang merupakan bagian dari perpustakaan zlib yang banyak digunakan (juga dikembangkan oleh Adler). Adler-32 tidak dapat diandalkan seperti pemeriksaan redundansi siklik 32-bit , tetapi - setidaknya dalam perangkat lunak - lebih cepat dan lebih mudah untuk diterapkan.

Definisi

Misalkan B = [b 1 , ⋯, b n ] menjadi array byte.

Checkum Adler-32 B didefinisikan sebagai hasil dari rendah + 65536 × tinggi , di mana:

  • rendah: = ((1 + b 1 + ⋯ + b n ) mod 65521)

  • tinggi: = (((1 + b 1 ) + (1 + b 1 + b 2 ) + ⋯ (1 + b 1 + ⋯ + b n )) mod 65521)

Tugas

Diberikan array byte sebagai input, hitung dan kembalikan checksum Adler-32-nya, patuhi yang berikut.

  • Anda dapat mengambil input sebagai array byte atau bilangan bulat, atau sebagai string.

    Dalam kedua kasus, hanya byte yang sesuai dengan karakter ASCII yang dapat dicetak yang akan muncul di input.

    Anda dapat mengasumsikan bahwa panjang input akan memenuhi 0 <panjang ≤ 4096 .

  • Jika Anda memilih untuk mencetak output, Anda dapat menggunakan basis positif apa pun hingga dan termasuk 256.

    Jika Anda memilih unary, pastikan interpreter dapat menangani hingga 2 32 - 983056 byte output pada mesin dengan 16 GiB RAM.

  • Built-in yang menghitung checksum Adler-32 dilarang.

  • Aturan standar berlaku.

Uji kasus

String:     "Eagles are great!"
Byte array: [69, 97, 103, 108, 101, 115, 32, 97, 114, 101, 32, 103, 114, 101, 97, 116, 33]
Checksum:   918816254

String:     "Programming Puzzles & Code Golf"
Byte array: [80, 114, 111, 103, 114, 97, 109, 109, 105, 110, 103, 32, 80, 117, 122, 122, 108, 101, 115, 32, 38, 32, 67, 111, 100, 101, 32, 71, 111, 108, 102]
Checksum:   3133147946

String:     "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
Byte array: [126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126]
Checksum:   68095937

String:     <1040 question marks>
Byte array: <1040 copies of 63>
Checksum:   2181038080

7
Saya akan mencatat bahwa banyak jawaban di sini akan gagal dengan urutan input besar atau sangat besar ketika mereka melimpah jumlah integer 32 atau 64-bit, karena menunda operasi modulo sampai setelah jumlah dihitung. Implementasi yang benar-benar patuh perlu melakukan operasi modulo setidaknya secara berkala agar jumlah tidak meluap. Bilangan bulat bertanda 32-bit akan melimpah setelah hanya 4.096 0xff. Bilangan bulat bertanda 64-bit akan melimpah setelah 256 MiB 0xff's.
Mark Adler

@MarkAdler Hm, titik adil. Karena saya tidak menentukan bahwa solusi harus bekerja untuk string panjang yang sewenang-wenang dan saya tidak ingin membatalkan jawaban yang ada, saya akan menetapkan batas untuk panjang input.
Dennis

@ Markerler Saya tidak berpikir itu penting. Saya cukup yakin bahwa overflow (menandatangani bilangan bulat 32-bit) hanya dapat terjadi dengan 4104 atau lebih byte input, karena nilai maksimum tinggi sebelum modulo adalah n * (n + 1) / 2 * 255 + n . Selain itu, tantangan membatasi input ke byte yang sesuai dengan karakter ASCII yang dapat dicetak.
Dennis

Kami juga dapat mengizinkan bahasa untuk melimpahi tipe numerik mereka, dan hanya mensyaratkan bahwa hasil yang dikembalikan setara, terhitung untuk melimpah, ke hasil yang benar.
mil

1
@PeterCordes Ya, array 32-bit int sangat baik. Setidaknya menurut saya, pengiriman harus fokus pada golf algoritme, dan memberi perhatian sesedikit mungkin kepada I / O.
Dennis

Jawaban:


3

Jelly, 19 17 byte

+\,S‘S€%65521ḅ⁹²¤

Cobalah online!

+\,S‘S€%65521ḅ⁹²¤    Main monadic chain. Takes array as only argument.

                     The array is shown here as [b1 b2 ... bn].
+\                   Reduce by addition (+) while returning immediate results.
                         yields [b1 b1+b2 ... b1+b2+...+bn].

  ,                  Concatenate with...
   S                 the sum of the argument.
                         yields [[b1 b1+b2 ... b1+b2+...+bn] b1+b2+...+bn].

    ‘                Increment [each].
                         yields [[1+b1 1+b1+b2 ... 1+b1+b2+...+bn] 1+b1+b2+...+bn].

     S€              Sum each list.
                         yields [[1+b1+1+b1+b2+...+1+b1+b2+...+bn] 1+b1+b2+...+bn].

       %65521        Modulo [each] by 65521.

             ḅ⁹²¤    Convert from base    65536    to integer.
              ⁹                        256
               ²                           squared

Lebih baik lagi:⁹²¤
Dennis

1
@ Dennis Saya telah outgolfed 18 byte Anda saat itu.
Bocor Biarawati

1
Nah, kamu sudah kalah besar ...
Leaky Nun

64

Mathematica, 46 byte

{1,4^8}.Fold[##+{0,#&@@#}&,{1,0},#]~Mod~65521&

Fungsi anonim yang mengambil array integer dan mengembalikan Adler-32, dengan beberapa peningkatan dari miles dan Martin (lihat komentar).

miles 'juga 46 byte , tetapi lebih cepat:

{1,4^8}.{Tr@#+1,Tr[Accumulate@#+1]}~Mod~65521&

37
... Apakah Anda baru saja membuat algoritma terkenal Anda sendiri?
Mego

25
Maafkan saya jika saya sedikit kaget. Tidak setiap hari Anda melihat nama besar dalam rekayasa perangkat lunak di situs kecil kami yang sederhana. Selamat bergabung!
Mego

6
Tidak terlalu besar.
Mark Adler

3
Jika Anda bermaksud saya, ini adalah pertama kalinya saya berpikir untuk mengimplementasikan Adler-32 di Mathematica.
Mark Adler

9
Atau mungkin Anda sudah menyiapkan solusi ini sejak Anda bergabung dengan Code Golf, hanya menunggu untuk ditanyakan. "Akhirnya!" ;-)
Antti Haapala

13

Julia, 73 46 byte

x->[sum(x)+1;sum(cumsum(x)+1)]%65521⋅[1;4^8]

Ini adalah fungsi anonim yang menerima array dan mengembalikan integer. Untuk menyebutnya, tetapkan ke variabel.

Kami menggabungkan sum(x) + 1dan sum(cumsum(x) + 1)menjadi sebuah array, di mana xarray input, dan mengambil masing-masing modulo 65521. Kami kemudian menghitung produk titik dengan 1 dan 4 8 , yang memberi kita (sum(x) + 1) + 4^8 * sum(cumsum(x) + 1), yang persis rumus Adler-32.

Cobalah online!(Termasuk semua kasus uji)

Disimpan 27 byte berkat Sp3000 dan Dennis!


Wow, itu sangat pintar.
kucing

@cat Saya punya Sp3000 dan Dennis untuk berterima kasih atas sebagian besar kepintarannya. :)
Alex A.

11

x86-64 fungsi kode mesin: 33 32 byte (atau 31 30 byte dengan int[]input, bukan char[])

fungsi kode mesin x86-32: 31 byte

Sebagai fragmen kode inline-asm GNU C: menyimpan 2B 1B (hanya retinsn).

Sumber dan test driver yang dikomentari di github

Versi 64bit dapat dipanggil langsung dari C dengan standar Sistem V x86-64 ABI (menggunakan 2 dummy args untuk mendapatkan args di regs yang saya inginkan). Konvensi panggilan khusus tidak biasa untuk kode asm, jadi ini adalah fitur bonus.

Kode mesin 32bit menghemat 1B, karena menggabungkan bagian tinggi dan rendah dengan push16/push16 => pop32hanya bekerja dalam mode 32bit. Fungsi 32bit membutuhkan konvensi pemanggilan kustom. Kita seharusnya tidak berpegang teguh pada itu, tetapi panggilan dari C membutuhkan fungsi wrapper.

Setelah memproses 4096 ~(ASCII 126) byte high = 0x3f040000, low = 0x7e001,. Jadi highbit yang paling signifikan belum ditetapkan. Kode saya mengambil keuntungan dari ini, masuk eaxke edx:eaxdengan cdqsebagai cara memusatkan perhatian edx.

# See the NASM source below
0000000000401120 <golfed_adler32_amd64>:
  401120:       31 c0                   xor    eax,eax
  401122:       99                      cdq    
  401123:       8d 7a 01                lea    edi,[rdx+0x1]
0000000000401126 <golfed_adler32_amd64.byteloop>:
  401126:       ac                      lods   al,BYTE PTR ds:[rsi]
  401127:       01 c7                   add    edi,eax
  401129:       01 fa                   add    edx,edi
  40112b:       e2 f9                   loop   401126 <golfed_adler32_amd64.byteloop>
000000000040112d <golfed_adler32_amd64.end>:
  40112d:       66 b9 f1 ff             mov    cx,0xfff1
  401131:       92                      xchg   edx,eax
  401132:       99                      cdq    
  401133:       f7 f1                   div    ecx
  401135:       52                      push   rdx
  401136:       97                      xchg   edi,eax
  401137:       99                      cdq    
  401138:       f7 f1                   div    ecx
  40113a:       66 52                   push   dx      # this is the diff from last version: evil push/pop instead of shift/add
  40113c:       58                      pop    rax
  40113d:       66 5a                   pop    dx
  40113f:       c3                      ret    
0000000000401140 <golfed_adler32_amd64_end>:

0x40 - 0x20 = 32 byte.


Sumber NASM yang dikomentari:

Trik:

  • xchg eax, r32adalah satu byte; lebih murah daripada mov. 8086 membutuhkan data dalam kapak untuk hal-hal yang jauh lebih banyak daripada> = 386, sehingga mereka memutuskan untuk menghabiskan banyak ruang opcode pada yang sekarang-jarang digunakan xchg ax, r16.

  • Mencampur push64 dan push16 untuk menggabungkan tinggi dan rendah ke dalam satu register menyimpan instruksi perpindahan data reg-reg sekitar dua divdetik. Versi 32bit dari trik ini bekerja lebih baik: push16 / push16 / pop32totalnya hanya 5B, bukan 6.

Karena kita push / pop, ini tidak aman untuk asline inm di SysV amd64 ABI (dengan zona merah) .

golfed_adler32_amd64_v3:   ; (int dummy, const char *buf, int dummy, uint64_t len)

    ;; args: len in rcx,  const char *buf in rsi
    ;; Without dummy args, (unsigned len, const char *buf),  mov ecx, edi is the obvious solution, costing 2 bytes

    xor     eax,eax         ; scratch reg for loading bytes
    cdq                     ; edx: high=0
    lea     edi, [rdx+1]    ; edi: low=1
    ;jrcxz  .end            ; We don't handle len=0.  unlike rep, loop only checks rcx after decrementing
.byteloop:
    lodsb                   ; upper 24b of eax stays zeroed (no partial-register stall on Intel P6/SnB-family CPUs, thanks to the xor-zeroing)
    add     edi, eax        ; low += zero_extend(buf[i])
    add     edx, edi        ; high += low
    loop   .byteloop
.end:
    ;; exit when ecx = 0, eax = last byte of buf
    ;; lodsb at this point would load the terminating 0 byte, conveniently leaving eax=0

    mov     cx, 65521       ; ecx = m = adler32 magic constant.  (upper 16b of ecx is zero from the loop exit condition.  This saves 1B over mov r32,imm32)
    ;sub    cx, (65536 - 65521) ; the immediate is small enough to use the imm8 encoding.  No saving over mov, though, since this needs a mod/rm byte

    xchg    eax, edx        ; eax = high,  edx = buf[last_byte]
    cdq                     ; could be removed if we could arrange things so the loop ended with a load of the 0 byte

    div     ecx             ; div instead of idiv to fault instead of returning wrong answers if high has overflowed to negative.  (-1234 % m is negative)
    push    rdx             ; push high%m and 6B of zero padding

    xchg    eax, edi        ; eax=low
    cdq
    div     ecx             ; edx = low%m

    ;; concatenate the two 16bit halves of the result by putting them in contiguous memory
    push    dx              ; push low%m with no padding
    pop     rax             ; pop  high%m << 16 | low%m   (x86 is little-endian)

    pop     dx              ; add rsp, 2 to restore the stack pointer

    ;; outside of 16bit code, we can't justify returning the result in the dx:ax register pair
    ret
golfed_adler32_amd64_end_v3:

Saya juga dianggap menggunakan rcxsebagai indeks array, bukannya memiliki dua loop counter, tetapi adler32 (s)! = Adler32 (terbalik (s)). Jadi kami tidak bisa menggunakan loop. Menghitung dari -len hingga nol dan menggunakan movzx r32, [rsi+rcx]terlalu banyak byte.

Jika kita ingin mempertimbangkan untuk menambahkan pointer sendiri, kode 32bit mungkin adalah cara yang harus dilakukan. Bahkan ABI x32 (pointer 32-bit) tidak cukup, karena inc esi2B pada amd64, tetapi 1B pada i386. Tampaknya sulit untuk mengalahkan xor eax,eax/ lodsb/ loop: 4B total untuk mendapatkan setiap elemen pada gilirannya nol-diperpanjang menjadi eax. inc esi/ movzx r32, byte [esi]/loop adalah 5B.

scasadalah pilihan lain untuk menambah pointer dengan instruksi 1B dalam mode 64bit. ( rdi/ edibukannya rsi, jadi kami akan mengambil pointer pointer di rdi). Namun, kami tidak dapat menggunakan hasil flag scassebagai kondisi loop, karena kami tidak ingin mempertahankan eax zeroed. Alokasi register yang berbeda mungkin dapat menyimpan byte setelah loop.


int[] memasukkan

Pengambilan fungsi penuh uint8_t[]adalah jawaban "utama", karena ini merupakan tantangan yang lebih menarik. Membongkar keint[] adalah hal yang tidak masuk akal untuk meminta penelepon kami melakukannya dalam bahasa ini, tetapi hal itu menghemat 2B.

Jika kita mengambil input kita sebagai array bilangan bulat 32bit, kita dapat menyimpan satu byte dengan mudah (gunakan lodsddan ganti xor eax,eax / cdqhanya denganxor edx,edx ).

Kita dapat menyimpan byte lain dengan memusatkan edx dengan lodsd/ cdq, dan mengatur ulang loop sehingga memuat elemen 0 terminating sebelum keluar. (Kami masih menganggap itu ada, meskipun ini adalah array int, bukan string).

; untested: I didn't modify the test driver to unpack strings for this
golfed_adler32_int_array:
    ; xor   edx,edx
    lodsd                   ; first element. only the low byte non-zero
    cdq                     ; edx: high=0
    lea     edi, [rdx+1]    ; edi: low=1
    ;jrcxz  .end            ; handle len=0?  unlike rep, loop only checks rcx after decrementing
.intloop:
    add     edi, eax        ; low += buf[i]
    add     edx, edi        ; high += low
    lodsd                   ; load buf[i+1] for next iteration
    loop   .intloop
.end:
    ;; exit when ecx = 0, eax = terminating 0

    xchg    eax, edx
    ;cdq               ; edx=0 already, ready for div
    ; same as the char version

Saya juga membuat versi yang belum diuji yang menggunakan scasd(versi 1B add edi,4) dan add eax, [rdi]bukannya lodsd, tetapi juga 30 byte. Penghematan dari memiliki highdi eax pada akhir loop diimbangi oleh kode yang lebih besar di tempat lain. Ini memiliki keuntungan tidak tergantung pada 0elemen terminating dalam input, yang mungkin tidak masuk akal untuk array yang tidak dibongkar dimana kita juga diberi panjangnya secara eksplisit.


C ++ 11 test driver

Lihat tautan github. Jawaban ini menjadi terlalu besar, dan driver tes mendapat lebih banyak fitur dengan kode yang lebih besar.


2
Saya memperbolehkan integer alih-alih byte terutama karena banyak bahasa bahkan tidak memiliki tipe byte. Bilangan bulat 32-bit mungkin merupakan pilihan yang tidak wajar untuk perakitan, tetapi golf kode adalah tentang memeras byte terakhir sambil tetap mengikuti aturan. Jika pilihan "tidak wajar" mengarah ke jumlah byte yang lebih rendah, saya akan mengatakan pergi untuk itu.
Dennis

@ Dennis: Saya mengerti perlunya aturan untuk beberapa bahasa. Saya berharap ada cara agar aturan hanya membiarkan Anda menggunakan int[]jika perlu, atau menyimpan lebih dari 4 byte kode atau sesuatu. Saya tidak punya masalah menghadirkan solusi untuk adler32(int[])masalah ini, tetapi saya merasa adler32(char[])masalahnya lebih menarik, karena itu adalah fungsi adler32 yang sebenarnya. Itu yang saya benar-benar ingin menjadi golf di ASM. (Dan saya ingin sekali menyimpan satu byte lagi, karena dalam kehidupan nyata asm, 33 byte = 48 byte jika fungsi selanjutnya menggunakan ALIGN 16). Saya kira saya akan terus bermain golf keduanya.
Peter Cordes

@ Dennis: juga, apakah kita perlu menangani kasus len = 0? Saya menghemat 2B dengan menggunakan do{}while(--len)gaya loop bukan a while(len--){}.
Peter Cordes

4
Ketika sampai pada penjelasan, semakin detail, semakin baik.
Dennis

3
@ kucing: Tidak, saya tidak merasa sakit. Saya tidak akan menghabiskan waktu saya menulis jawaban Stackoverflow untuk pertanyaan asm / kinerja, dan memperbarui wiki tag x86 jika saya melakukannya: P Jika Anda ingin tahu mengapa kode berjalan lambat atau cepat, Anda harus melihat dan memahami asm. Setelah Anda melakukannya sebentar, Anda mulai melihat kapan kompiler dapat membuat kode lebih cepat ... dan akhirnya Anda mulai berpikir tentang bagaimana kompiler dapat mengkompilasi kode saat Anda menulisnya. Mengoptimalkan ukuran kode alih-alih kinerja kadang-kadang merupakan perubahan yang menarik.
Peter Cordes

8

MATL , 22 byte

tsQwYsQsh16W15-\l8Mh*s

Input dapat berupa array angka atau string ASCII yang sesuai.

Cobalah online!

Penjelasan

t       % Take array or string as input. Duplicate
sQ      % Sum all its values, and add 1
wYsQs   % Swap. Cumulative sum, add 1, sum
h       % Concatenate horizontally
16W     % 2^16: gives 65536
15-     % Subtract 15: gives 65521
\       % Element-wise modulo operation
l       % Push 1
8M      % Push 65536 again
h       % Concatenate horizontally: gives array [1, 65535]
*s      % Element-wise multiplication and sum. Display

7

Sebenarnya, 36 byte

;Σu@;╗lR`╜HΣu`MΣk`:65521@%`M1#84ⁿ@q*

Cobalah online!

Penjelasan:

;Σu@;╗lR`╜HΣu`MΣk`:65521@%`M1#84ⁿ@q*
;Σu                                   sum(input)+1
   @;╗lR                              push a copy of input to reg0, push range(1, len(input)+1)
        `╜HΣu`M                       map over range: sum(head(reg0,n))+1
               Σk                     sum, combine lower and upper into a list
                 `:65521@%`M          modulo each by 65521
                            1#84ⁿ@q*  dot product with [1,4**8]

7

Java, 84 byte

long a(int[]i){long a=1,b=0;for(int p:i)b=(b+(a=(a+p)%(p=65521)))%p;return b<<16|a;}

Jika solusi Java selalu dianggap sebagai kode yang dapat dikompilasi, beri tahu saya.

Tidak disatukan

long a(int[] i) {
    long a = 1, b = 0;
    for (int p : i) b = (b + (a = (a + p) % (p = 65521))) % p;
    return b << 16 | a;
}

Catatan

Anda harus mengonversi input Stringmenjadi int[]( int[]lebih pendek satu byte dari byte[]atauchar[] ).

Keluaran

String:     "Eagles are great!"
Byte Array: [69, 97, 103, 108, 101, 115, 32, 97, 114, 101, 32, 103, 114, 101, 97, 116, 33]
Checksum:   918816254
Expected:   918816254

String:     "Programming Puzzles & Code Golf"
Byte Array: [80, 114, 111, 103, 114, 97, 109, 109, 105, 110, 103, 32, 80, 117, 122, 122, 108, 101, 115, 32, 38, 32, 67, 111, 100, 101, 32, 71, 111, 108, 102]
Checksum:   3133147946
Expected:   3133147946

String:     "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
Byte Array: [126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126]
Checksum:   68095937
Expected:   68095937

String:     "?????????...?"
Byte Array: [63, 63, 63, 63, 63, 63, 63, 63, 63, ...,63]
Checksum:   2181038080
Expected:   2181038080

1
Jawaban yang bagus, dan selamat datang di situs! Juga, solusi yang tidak lengkap dan dapat dikompilasi baik-baik saja kecuali tantangannya secara eksplisit menyatakan bahwa itu harus menjadi program penuh. Ini adalah fungsi penuh, jadi itu penting.
DJMcMayhem

6

Piet, 120 Codel codelsize 1

Dengan ukuran kode 20:

codelsize 20

Catatan / Bagaimana cara kerjanya?

  • Karena tidak mungkin menggunakan array atau string sebagai input, program ini bekerja dengan mengambil serangkaian bilangan bulat (mewakili karakter ascii) sebagai input. Saya berpikir tentang menggunakan input karakter pada awalnya tetapi berjuang untuk menemukan solusi yang bagus untuk penghentian, jadi sekarang berakhir ketika ada angka yang lebih kecil dari 1 dimasukkan. Awalnya hanya nilai negatif untuk penghentian, tetapi saya harus mengubah inisialisasi setelah menulis program, jadi sekarang saya tidak bisa cocok dengan yang diperlukan 2, hanya 1(26/45 pada gambar jejak). Ini tidak masalah karena karena sesuai aturan tantangan, hanya karakter ascii yang dapat dicetak yang diizinkan.

  • Berjuang untuk waktu yang lama dengan memasuki kembali loop, meskipun pada akhirnya saya menemukan solusi yang cukup elegan. Tidak pointeratau switchoperasi, hanya interpreter berjalan ke dinding sampai transisi kembali ke codel hijau untuk membaca input (43-> 44 pada gambar jejak).

  • Pengakhiran loop dilakukan dengan menduplikasi input terlebih dahulu, menambahkan 1 dan kemudian memeriksa apakah lebih besar dari 1. Jika ya, pemilih kode dipicu dan eksekusi berlanjut di jalur yang lebih rendah. Jika tidak, program akan melanjutkan ke kiri (Kode kuning cerah, 31/50 pada gambar jejak).

  • Ukuran input yang didukung bergantung pada implementasi juru bahasa, meskipun akan mungkin untuk mendukung input yang besar dan sewenang-wenang dengan juru bahasa yang tepat (Misalnya, juru bahasa Java yang menggunakan BigIntegernilai internal)

  • Hanya melihat bahwa pengaturan termasuk yang tidak perlu DUP dan CC(7-> 8-> 9 di gambar jejak). Tidak tahu bagaimana itu terjadi. Ini secara efektif adalah noop sekalipun, ia mengaktifkan pemilih kode 16 kali yang menghasilkan tidak ada perubahan.

Npiet melacak gambar

Setup dan loop pertama:

starttrace

Pengakhiran loop, output dan keluar:

endtrace

Keluaran

Maafkan saya jika saya hanya memasukkan satu output, hanya butuh waktu lama untuk memasukkan: ^)

String: "Eagles are great!"

PS B:\Marvin\Desktop\Piet> .\npiet.exe adler32.png
? 69
? 97
? 103
? 108
? 101
? 115
? 32
? 97
? 114
? 101
? 32
? 103
? 114
? 101
? 97
? 116
? 33
? -1
918816254

Jejak Npiet untuk [65, -1]

trace: step 0  (0,0/r,l nR -> 1,0/r,l dR):
action: push, value 4
trace: stack (1 values): 4

trace: step 1  (1,0/r,l dR -> 2,0/r,l dB):
action: duplicate
trace: stack (2 values): 4 4

trace: step 2  (2,0/r,l dB -> 3,0/r,l nM):
action: multiply
trace: stack (1 values): 16

trace: step 3  (3,0/r,l nM -> 4,0/r,l nC):
action: duplicate
trace: stack (2 values): 16 16

trace: step 4  (4,0/r,l nC -> 5,0/r,l nY):
action: duplicate
trace: stack (3 values): 16 16 16

trace: step 5  (5,0/r,l nY -> 6,0/r,l nM):
action: duplicate
trace: stack (4 values): 16 16 16 16

trace: step 6  (6,0/r,l nM -> 7,0/r,l nC):
action: duplicate
trace: stack (5 values): 16 16 16 16 16

trace: step 7  (7,0/r,l nC -> 8,0/r,l nY):
action: duplicate
trace: stack (6 values): 16 16 16 16 16 16

trace: step 8  (8,0/r,l nY -> 9,0/r,l lB):
action: switch
trace: stack (5 values): 16 16 16 16 16
trace: stack (5 values): 16 16 16 16 16

trace: step 9  (9,0/r,l lB -> 10,0/r,l dM):
action: multiply
trace: stack (4 values): 256 16 16 16

trace: step 10  (10,0/r,l dM -> 11,0/r,l nR):
action: multiply
trace: stack (3 values): 4096 16 16

trace: step 11  (11,0/r,l nR -> 12,0/r,l lY):
action: multiply
trace: stack (2 values): 65536 16

trace: step 12  (12,0/r,l lY -> 13,0/r,l lM):
action: duplicate
trace: stack (3 values): 65536 65536 16

trace: step 13  (13,0/r,l lM -> 14,0/r,l nM):
action: push, value 3
trace: stack (4 values): 3 65536 65536 16

trace: step 14  (14,0/r,l nM -> 15,0/r,l dM):
action: push, value 2
trace: stack (5 values): 2 3 65536 65536 16

trace: step 15  (15,0/r,l dM -> 16,0/r,l lC):
action: roll
trace: stack (3 values): 16 65536 65536

trace: step 16  (16,0/r,l lC -> 17,0/r,l nB):
action: sub
trace: stack (2 values): 65520 65536

trace: step 17  (17,0/r,l nB -> 18,0/r,l dB):
action: push, value 1
trace: stack (3 values): 1 65520 65536

trace: step 18  (18,0/r,l dB -> 19,0/r,l dM):
action: add
trace: stack (2 values): 65521 65536

trace: step 19  (19,0/r,l dM -> 19,1/d,r dC):
action: duplicate
trace: stack (3 values): 65521 65521 65536

trace: step 20  (19,1/d,r dC -> 18,1/l,l lC):
action: push, value 1
trace: stack (4 values): 1 65521 65521 65536

trace: step 21  (18,1/l,l lC -> 17,1/l,l nC):
action: push, value 1
trace: stack (5 values): 1 1 65521 65521 65536

trace: step 22  (17,1/l,l nC -> 16,1/l,l dB):
action: sub
trace: stack (4 values): 0 65521 65521 65536

trace: step 23  (16,1/l,l dB -> 15,1/l,l lB):
action: push, value 1
trace: stack (5 values): 1 0 65521 65521 65536

trace: step 24  (15,1/l,l lB -> 13,2/l,l dG):
action: in(number)
? 65
trace: stack (6 values): 65 1 0 65521 65521 65536

trace: step 25  (13,2/l,l dG -> 12,2/l,l dR):
action: duplicate
trace: stack (7 values): 65 65 1 0 65521 65521 65536

trace: step 26  (12,2/l,l dR -> 11,2/l,l lR):
action: push, value 1
trace: stack (8 values): 1 65 65 1 0 65521 65521 65536

trace: step 27  (11,2/l,l lR -> 10,2/l,l lY):
action: add
trace: stack (7 values): 66 65 1 0 65521 65521 65536

trace: step 28  (10,2/l,l lY -> 9,2/l,l nY):
action: push, value 1
trace: stack (8 values): 1 66 65 1 0 65521 65521 65536

trace: step 29  (9,2/l,l nY -> 8,1/l,r nB):
action: greater
trace: stack (7 values): 1 65 1 0 65521 65521 65536

trace: step 30  (8,1/l,r nB -> 7,1/l,r lY):
action: switch
trace: stack (6 values): 65 1 0 65521 65521 65536
trace: stack (6 values): 65 1 0 65521 65521 65536

trace: step 31  (7,1/l,l lY -> 6,2/l,l nY):
action: push, value 2
trace: stack (7 values): 2 65 1 0 65521 65521 65536

trace: step 32  (6,2/l,l nY -> 5,3/l,l dB):
action: pointer
trace: stack (6 values): 65 1 0 65521 65521 65536

trace: step 33  (5,3/r,l dB -> 7,4/r,l dM):
action: add
trace: stack (5 values): 66 0 65521 65521 65536

trace: step 34  (7,4/r,l dM -> 8,4/r,l dC):
action: duplicate
trace: stack (6 values): 66 66 0 65521 65521 65536

trace: step 35  (8,4/r,l dC -> 9,3/r,l lC):
action: push, value 3
trace: stack (7 values): 3 66 66 0 65521 65521 65536

trace: step 36  (9,3/r,l lC -> 10,3/r,l nC):
action: push, value 2
trace: stack (8 values): 2 3 66 66 0 65521 65521 65536

trace: step 37  (10,3/r,l nC -> 11,3/r,l dY):
action: roll
trace: stack (6 values): 0 66 66 65521 65521 65536

trace: step 38  (11,3/r,l dY -> 12,3/r,l dG):
action: add
trace: stack (5 values): 66 66 65521 65521 65536

trace: step 39  (12,3/r,l dG -> 13,3/r,l lG):
action: push, value 2
trace: stack (6 values): 2 66 66 65521 65521 65536

trace: step 40  (13,3/r,l lG -> 14,3/r,l nG):
action: push, value 1
trace: stack (7 values): 1 2 66 66 65521 65521 65536

trace: step 41  (14,3/r,l nG -> 15,3/r,l dR):
action: roll
trace: stack (5 values): 66 66 65521 65521 65536
trace: white cell(s) crossed - continuing with no command at 17,3...

trace: step 42  (15,3/r,l dR -> 17,3/r,l lB):

trace: step 43  (17,3/r,l lB -> 13,2/l,l dG):
action: in(number)
? -1
trace: stack (6 values): -1 66 66 65521 65521 65536

trace: step 44  (13,2/l,l dG -> 12,2/l,l dR):
action: duplicate
trace: stack (7 values): -1 -1 66 66 65521 65521 65536

trace: step 45  (12,2/l,l dR -> 11,2/l,l lR):
action: push, value 1
trace: stack (8 values): 1 -1 -1 66 66 65521 65521 65536

trace: step 46  (11,2/l,l lR -> 10,2/l,l lY):
action: add
trace: stack (7 values): 0 -1 66 66 65521 65521 65536

trace: step 47  (10,2/l,l lY -> 9,2/l,l nY):
action: push, value 1
trace: stack (8 values): 1 0 -1 66 66 65521 65521 65536

trace: step 48  (9,2/l,l nY -> 8,1/l,r nB):
action: greater
trace: stack (7 values): 0 -1 66 66 65521 65521 65536

trace: step 49  (8,1/l,r nB -> 7,1/l,r lY):
action: switch
trace: stack (6 values): -1 66 66 65521 65521 65536
trace: stack (6 values): -1 66 66 65521 65521 65536

trace: step 50  (7,1/l,r lY -> 6,1/l,r dY):
action: pop
trace: stack (5 values): 66 66 65521 65521 65536

trace: step 51  (6,1/l,r dY -> 4,1/l,r lY):
action: push, value 3
trace: stack (6 values): 3 66 66 65521 65521 65536

trace: step 52  (4,1/l,r lY -> 3,1/l,r nY):
action: push, value 2
trace: stack (7 values): 2 3 66 66 65521 65521 65536

trace: step 53  (3,1/l,r nY -> 2,1/l,r nM):
action: duplicate
trace: stack (8 values): 2 2 3 66 66 65521 65521 65536

trace: step 54  (2,1/l,r nM -> 1,1/l,r dG):
action: pointer
trace: stack (7 values): 2 3 66 66 65521 65521 65536

trace: step 55  (1,1/r,r dG -> 2,2/r,r lR):
action: roll
trace: stack (5 values): 65521 66 66 65521 65536

trace: step 56  (2,2/r,r lR -> 2,3/d,l nR):
action: push, value 1
trace: stack (6 values): 1 65521 66 66 65521 65536

trace: step 57  (2,3/d,l nR -> 2,4/d,l lC):
action: switch
trace: stack (5 values): 65521 66 66 65521 65536
trace: stack (5 values): 65521 66 66 65521 65536

trace: step 58  (2,4/d,r lC -> 2,5/d,r nM):
action: mod
trace: stack (4 values): 66 66 65521 65536

trace: step 59  (2,5/d,r nM -> 4,5/r,r dM):
action: push, value 3
trace: stack (5 values): 3 66 66 65521 65536

trace: step 60  (4,5/r,r dM -> 6,5/r,r lM):
action: push, value 2
trace: stack (6 values): 2 3 66 66 65521 65536

trace: step 61  (6,5/r,r lM -> 7,5/r,r nC):
action: roll
trace: stack (4 values): 65521 66 66 65536

trace: step 62  (7,5/r,r nC -> 8,5/r,r dM):
action: mod
trace: stack (3 values): 66 66 65536

trace: step 63  (8,5/r,r dM -> 11,5/r,r lM):
action: push, value 3
trace: stack (4 values): 3 66 66 65536

trace: step 64  (11,5/r,r lM -> 12,5/r,r nM):
action: push, value 1
trace: stack (5 values): 1 3 66 66 65536

trace: step 65  (12,5/r,r nM -> 13,5/r,r dC):
action: roll
trace: stack (3 values): 66 65536 66

trace: step 66  (13,5/r,r dC -> 14,5/r,r nB):
action: multiply
trace: stack (2 values): 4325376 66

trace: step 67  (14,5/r,r nB -> 15,5/r,r nM):
action: add
trace: stack (1 values): 4325442

trace: step 68  (15,5/r,r nM -> 16,5/r,r dB):
action: out(number)
4325442
trace: stack is empty
trace: white cell(s) crossed - continuing with no command at 19,5...

trace: step 69  (16,5/r,r dB -> 19,5/r,r nM):

5

C89, 70 byte

h,l,m=65521;A(char*B){h=0;l=1;while(*B)h+=l+=*B++;return h%m<<16|l%m;}

Untuk menguji (kompilasi dengan gcc -std=c89 -lm golf.c):

#include <stdio.h>
int main(int argc, char** argv) {
    printf("%u\n", A("Eagles are great!"));
    printf("%u\n", A("Programming Puzzles & Code Golf"));
    printf("%u\n", A("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"));
    return 0;
}

Apakah itu yang zlibterlihat sumbernya? Hm ...
kucing

1
Implementasi ini membuat titik awal yang bagus untuk versi as86 x86 saya.
Peter Cordes

Dapat menghemat 1 byte menggunakan forbukannya while:for(h=0,l=1;*B;)h+=l+=*B++;
ninjalj

5

Labyrinth , 37 36 32 31 byte

}?"{655:}21:}%=}){%{{36*+!
:++)

Cobalah online!

Input sebagai daftar bilangan bulat. Program berakhir dengan kesalahan (yang pesan kesalahannya masuk ke STDERR).

Penjelasan

Primer labirin:

  • Labyrinth memiliki dua tumpukan bilangan bulat presisi- utama , utama dan aux (iliary), yang awalnya diisi dengan jumlah nol tak terbatas (implisit).
  • Kode sumbernya menyerupai sebuah labirin, tempat penunjuk instruksi (IP) mengikuti koridor ketika bisa (bahkan di sekitar sudut). Kode dimulai pada karakter valid pertama dalam urutan membaca, yaitu di sudut kiri atas dalam kasus ini. Ketika IP datang ke segala bentuk persimpangan (yaitu beberapa sel yang berdekatan selain dari yang berasal dari), ia akan memilih arah berdasarkan bagian atas tumpukan utama. Aturan dasarnya adalah: belok kiri saat negatif, teruskan ke depan ketika nol, belok kanan saat positif. Dan ketika salah satu dari ini tidak mungkin karena ada dinding, maka IP akan mengambil arah yang berlawanan. IP juga berbalik ketika mengenai jalan buntu.
  • Digit diproses dengan mengalikan bagian atas tumpukan utama dengan 10 dan kemudian menambahkan digit. Untuk memulai nomor baru, Anda bisa menekan nol dengan _.

Meskipun kode dimulai dengan "ruang" 4x2, itu sebenarnya dua loop dua-dua terpisah yang diperas. IP kebetulan menempel satu loop pada satu waktu karena nilai stack.

Jadi kode dimulai dengan loop 2x2 (searah jarum jam) yang membaca input saat menghitung jumlah awalan:

}   Move last prefix sum over to aux.
?   Read an integer from STDIN or push 0 on EOF, which exits the loop.
+   Add current value to prefix sum.
:   Duplicate this prefix sum.

Sekarang kita memiliki semua jumlah awalan pada tumpukan aux , serta salinan jumlah atas semua nilai dan 0dari EOF pada main . Dengan itu, kita memasukkan loop 2x2 (searah jarum jam) yang menjumlahkan semua jumlah awalan untuk dihitung HIGH.

"   No-op. Does nothing.
{   Pull one prefix sum over from aux. When we're done, this fetches a 0,
    which exits the loop.
)   Increment prefix sum.
+   Add it to HIGH.

Stack utama sekarang memiliki LOW - 1dan HIGHnol, kecuali kita belum mengambil modulo. Sisa kode sepenuhnya linier:

655      Turn the zero into 655.
:}       Make a copy and shift it over to aux.
21       Turn the copy on main into 65521.
:}       Make a copy and shift it over to aux.
%        Take HIGH mod 65521.
=        Swap HIGH with the other copy of 65521 on aux.
}){      Move 65521 back to aux, increment LOW-1 to LOW, 
         move 65521 back to main.
%        Take LOW mod 65521.
{        Move HIGH back to main.
{        Move the other copy of 655 back to main.
36       Turn it into 65536.
*        Multiply HIGH by that.
+        Add it to LOW.
!        Print it.

IP sekarang menemui jalan buntu dan berbalik. The +dan *pada dasarnya tidak ada ops, karena angka nol di bagian bawah tumpukan. The 36sekarang ternyata bagian atas utama dalam 63, tetapi dua {{tarik dua nol dari aux di atasnya. Kemudian %coba bagi dengan nol yang mengakhiri program.

Perhatikan bahwa Labyrinth menggunakan bilangan bulat presisi arbitrer jadi tunda modulo sampai akhir jumlah tidak akan menyebabkan masalah dengan bilangan bulat bilangan bulat.


5

Python 2, 60 58 byte

H=h=65521
l=1
for n in input():l+=n;h+=l
print h%H<<16|l%H

Pendekatan yang cukup mudah. Ini adalah program lengkap yang mengambil daftar bilangan bulat melalui STDIN, mis [72, 105, 33].

(Terima kasih kepada @xnor untuk tip aliasing / inisialisasi yang luar biasa)


2
Anda dapat melakukan H=h=65521inisialisasi hsementara aliasing 65521.
xnor

4

J, 30 byte

+/(+65536&*)&(65521|+/)&:>:+/\

Ini mungkin bisa lebih padat dengan kereta yang berbeda.

Pemakaian

Di sini x $ ymembuat daftar dengan xsalinan y.

   f =: +/(+65536&*)&(65521|+/)&:>:+/\
   f 69 97 103 108 101 115 32 97 114 101 32 103 114 101 97 116 33
918816254
   f 80 114 111 103 114 97 109 109 105 110 103 32 80 117 122 122 108 101 115 32 38 32 67 111 100 101 32 71 111 108 102
3133147946
   f (32 $ 126)
68095937
   f (1040 $ 63)
2181038080
   f (4096 $ 255)
2170679522

Penjelasan

+/(+65536&*)&(65521|+/)&:>:+/\
f (           g           ) h     Monad train (f g h) y = (f y) g (h y)
+/                                Sum the input list
                           +/\    Sum each prefix of the input, forms a list
x     f   &   g   &:   h    y     Composed verbs, makes (g (h x)) f (g (h y))
                         >:       Increment the sum and increment each prefix sum
               (m f g) y          Hook, makes m f (g y)
                    +/            Sum the prefix sums
              65521|              Take the sum and prefix total mod 65521
    (f g) y                       Hook again
    65536&*                       Multiply the prefix total by 65536
                                  This is a bonded verb, it will only multiply
                                  using a fixed value now
   +                              Add the sum and scaled prefix total

4

Oktaf, 52 50 byte

Disimpan 2 byte berkat @LuisMendo

@(B)mod([sum(S=cumsum(B)+1),S(end)],65521)*[4^8;1]

Mengambil array bilangan bulat sebagai input.

rendah diambil dari elemen terakhir tinggi (sebelum penjumlahan) daripada menghitung jumlah secara eksplisit, menghemat total ... 1 byte !

Sampel dijalankan pada ideone .


@LuisMendo Ooh, saya lupa +B. Saya kira spec input mengatakan Anda dapat mengambil bilangan bulat, jadi mungkin saya hanya akan melakukannya.
Gelas

3

CJam, 30 29 byte

q~{1$+}*]:)_W>]1fb65521f%2G#b

Input sebagai daftar bilangan bulat.

Uji di sini.

Penjelasan

q~       e# Read and evaluate input.
{        e# Fold this block over the list, computing prefix sums.
  1$+    e#   Copy the last prefix and add the current element.
}*
]        e# Wrap the prefix sums in an array.
:)       e# Increment each. This will sum to HIGH.
_W>      e# Copy the list and truncate to only the last element, i.e.
         e# the sum of the entire input plus 1. This is LOW.
]        e# Wrap both of those lists in an array.
1fb      e# Sum each, by treating it as base 1 digits.
65521f%  e# Take each modulo 65521.
2G#b     e# Treat the list as base 65536 digits, computing 65536*HIGH + LOW.

3

Perl 6 , 60 byte

{(.sum+1)%65521+65536*((sum(1,*+.shift...->{!$_})-1)%65521)}

Penjelasan:

{
  # $_ is the implicit parameter for this lambda because this block doesn't have
  # an explicit parameter, and @_ isn't seen inside of it.
  # ( @_ takes precedence over $_ when it is seen by the compiler )

  # .sum is short for $_.sum
  ( .sum + 1 ) % 65521 + 65536
  *
  (
    (
      sum(

        # generate a sequence:

        1,         # starting with 1
        * + .shift # lambda that adds previous result (*) with $_.shift
        ...        # generate until:
        -> { !$_ } # $_ is empty

        # ^ I used a pointy block with zero parameters
        # so that the block doesn't have an implicit parameter
        # like the surrounding block

        # this is so that $_ refers to the outer $_

      ) - 1        # remove starting value
    ) % 65521
  )
}

Uji:

#! /usr/bin/env perl6
use v6.c;
use Test;

# give the lambda a name
my &Adler32 = {(.sum+1)%65521+65536*((sum(1,*+.shift...->{!$_})-1)%65521)}

my @tests = (
  (  918816254,  'Eagles are great!'),
  ( 3133147946,  'Programming Puzzles & Code Golf'),
  (   68095937,  '~' x 32,     "'~' x 32"),
  ( 2181038080,  63 xx 1040,   "'?' x 1040"),
);

plan +@tests;

for @tests -> ($checksum, $input, $gist? ) {
  my @array := do given $input {
    when Str { .encode.Array }
    default { .Array }
  }

  is Adler32(@array), $checksum, $gist // $input.perl
}
1..4
ok 1 - "Eagles are great!"
ok 2 - "Programming Puzzles \& Code Golf"
ok 3 - '~' x 32
ok 4 - '?' x 1040

3

Python 3 (79 byte)

Berdasarkan solusi R. Kap.

lambda w,E=65521:(1+sum(w))%E+(sum(1+sum(w[:i+1])for i in range(len(w)))%E<<16)

Saya mengganti perkalian dengan satu shift dan melepaskan sepasang tanda kurung.

Karena saya tidak dapat memposting komentar, saya membuat jawaban baru.


3

Skema, 195 byte

(define(a b)(+(let L((b b)(s 1))(if(=(length b)0)s(L(cdr b)(modulo(+ s(car b))65521))))(* 65536(let H((b b)(s 1)(t 0))(if(=(length b)0)t(let((S(+ s(car b))))(H(cdr b)S(modulo(+ t S)65521))))))))

Jika bukan karena semua kurung itu ...


3

Haskell, 54 50 byte

m=(`mod`65521).sum
g x=m(-1:scanl(+)1x)*4^8+m(1:x)

Contoh penggunaan: g [69,97,103,108,101,115,32,97,114,101,32,103,114,101,97,116,33]-> 918816254.

scanltermasuk nilai awal (-> 1) dalam daftar (-> [1,1+b1,1+b1+b2,..]), jadi sumdimatikan oleh 1, yang diperbaiki oleh prepending-1 ke daftar sebelum menjumlahkan.

Sunting: Terima kasih @xnor untuk 4 byte.


Sepertinya Anda dapat mengekstrak keluar penjumlahan ke m: m=(`mod`65521).sum g x=m(-1:scanl(+)1x)*4^8+m(1:x). Mungkin ada cara yang lebih baik untuk memperbaiki jumlah daripada mengawali.
xnor

3

JavaScript (ES7), 52 50 byte

a=>a.map(b=>h+=l+=b,h=0,l=1)&&l%65521+h%65521*4**8

ES6 membutuhkan 51 byte (ganti 4 ** 8 dengan 65536). Jika Anda menginginkan versi string, maka untuk 69 byte:

s=>[...s].map(c=>h+=l+=c.charCodeAt(),h=0,l=1)&&l%65521+h%65521*65536

Sunting: Disimpan 2 byte berkat @ user81655.


3

Menerima fungsi ARM Thumb-2 uint8_t[] : 40 byte (36B untuk ABI non-standar danint[] )

Fitur-fitur: modulo yang tidak ditangguhkan, sehingga input ukuran arbitrer baik-baik saja. Tidak benar-benar menggunakan instruksi pembagian, jadi itu tidak lambat. (err, setidaknya bukan karena alasan itu: P)

Penghematan dari mengikuti aturan yang tidak terlalu ketat:

  • -2B jika kita tidak harus menyimpan register sebelum menggunakannya.
  • -2B untuk meminta penelepon membongkar byte ke a uint32_t[] array.

Jadi, kasus terbaik adalah 36B.

// uint8_t *buf in r0,  uint32_t len in r1
00000000 <adler32arm_golf2>:
   0:   b570            push    {r4, r5, r6, lr} //
   2:   2201            movs    r2, #1          // low
   4:   2300            movs    r3, #0          // high
   6:   f64f 75f1       movw    r5, #65521      ; 0xfff1 = m
0000000a <adler32arm_golf2.byteloop>:
   a:   f810 4b01       ldrb.w  r4, [r0], #1    // post-increment byte-load
   e:   4422            add     r2, r4          // low += *B
  10:   4413            add     r3, r2          // high += low
  12:   42aa            cmp     r2, r5          // subtract if needed instead of deferred modulo
  14:   bf28            it      cs
  16:   1b52            subcs   r2, r2, r5
  18:   42ab            cmp     r3, r5
  1a:   bf28            it      cs              // Predication in thumb mode is still possible, but takes a separate instruction
  1c:   1b5b            subcs   r3, r3, r5
  1e:   3901            subs    r1, #1          // while(--len)
  20:   d1f3            bne.n   a <.byteloop2>
  22:   eac2 4003       pkhbt   r0, r2, r3, lsl #16   // other options are the same size: ORR or ADD.
  26:   bd70            pop     {r4, r5, r6, pc}  // ARM can return by popping the return address (from lr) into the pc; nifty
00000028 <adler32arm_end_golf2>:

0x28 = 40 byte


Catatan:

Alih-alih log%mpada akhirnya, kita melakukannya if(low>=m) low-=mdi dalam loop. Jika kita melakukan rendah sebelum tinggi, kita tahu bahwa tidak ada yang bisa melebihi 2*m, jadi modulo hanya masalah pengurangan atau tidak. A cmpdan predicated subhanya 6B dalam mode Thumb2. Idi standar untuk% adalah 8B dalam mode Thumb2:

UDIV R2, R0, R1         // R2 <- R0 / R1
MLS  R0, R1, R2, R0     // R0 <- R0 - (R1 * R2 )

adler(char *)Versi panjang implisit adalah ukuran kode yang sama dengan panjang eksplisitadler(uint8_t[], uint32_t len) . Kita dapat mengatur flag untuk kondisi loop-exit dengan satu instruksi 2B.

Versi implisit-panjang memiliki keuntungan bekerja dengan benar dengan string kosong, daripada mencoba untuk mengulang 2 ^ 32 kali.


berkumpul / kompilasi dengan:

arm-linux-gnueabi-as --gen-debug -mimplicit-it=always -mfloat-abi=soft -mthumb adler32-arm.S

atau

arm-linux-gnueabi-g++ -Wa,-mimplicit-it=always -g -static -std=gnu++14 -Wall -Wextra -Os -march=armv6t2 -mthumb -mfloat-abi=soft test-adler32.cpp -fverbose-asm adler32-arm.S -o test-adler32
qemu-arm ./test-adler32

Tanpa -static, proses yang berjalan di bawah qemu-armtidak menemukan itu penghubung dinamis. (Dan ya, saya menginstal ARM cross-devel setup hanya untuk jawaban ini, karena saya pikir ide predicated-kurangi saya rapi.) Di amd64 Ubuntu, instal gcc-arm-linux-gnueabi,g++-arm-linux-gnueabi . Saya menemukan gdb-arm-none-eabisemacam bekerja menghubungkan ke qemu-arm -g port.

Sumber yang dikomentari:

// There's no directive to enable implicit-it=always

// gcc uses compiler uses these in its output
.syntax unified
.arch armv8-a
.fpu softvfp

.thumb      @ aka .code 16

.p2align 4
.globl adler32arm_golf    @ put this label on the one we want to test

.thumb_func
adler32arm_golf:
adler32arm_golf2:   @ (uint8_t buf[], uint32_t len)
        @ r0 = buf
        @ r1 = len
        push    {r4, r5, r6, lr}   @ even number of regs keeps the stack aligned.  Good style? since there's no code-size saving

        movs    r2, #1          @ r2: low
        movs    r3, #0          @ r3: high
                                @ r4 = tmp for loading bytes
        movw    r5, #65521      @ r5: modulo constant

adler32arm_golf2.byteloop2:
        ldrb    r4, [r0], #1    @ *(buf++) post-increment addressing.  4B encoding
        @ldrb    r4, [r0, r1]   @ 2B encoding, but unless we make the caller pass us buf+len and -len, it needs extra code somewhere else
        @ldmia   r0!, {r4}      @ int[] version:  r4 = [r0]; r0+=4;  post-increment addressing.  2B encoding.

        add     r2, r2, r4      @ low += tmp
        add     r3, r3, r2      @ high += low;   // I think it's safe to do this before the modulo range-reduction for low, but it would certainly work to put it after.

        cmp     r2, r5
        subhs   r2, r5          @ if(low>=m) low-=m;   @ 6B total for %.  predicated insns require an IT instruction in thumb2

        cmp     r3, r5
        subhs   r3, r5          @ if(high>=m) high-=m;  // equivalent to high %= m.

        @sub    r1, #1          @ 4B encoding: sub.w to not set flags with immediate
        subs    r1, #1          @ len-- and set flags.  2B encoding
        @cmp    r4, #0          @ null-termination check. 2B encoding
        bne     adler32arm_golf2.byteloop2

@        udiv    r0, r2, r5            @ normal way to do one of the modulos
@        mls     r2, r5, r0, r2         @ r2 = low % m.  8B total for %

        PKHBT   r0, r2, r3, lsl #16     @ 4B   r0 = [ high%m <<16  |   low%m  ]
        @orr     r0, r0, r4, lsl #16    @ 4B
        @orr     r0, r0, r4             @ 4B
        @add     r0, r2, r3, lsl #16    @ 4B
        @add     r0, r0, r4             @ 2B
        pop     {r4, r5, r6, pc}        @ ARM can return by popping the return address (saved from lr) into pc.  Nifty
adler32arm_end_golf2:

test-adler32.cppmemiliki kasus uji yang sama dan main()untuk jawaban x86-64 saya, tetapi memulai dengan cara ini:

#include <stdint.h>
uint32_t adler32_simple(const uint8_t *B) {
  const uint32_t m=65521;

  uint32_t h=0, l=1;
  do {
    l += *B++;        // Borrowed from orlp's answer, as a simple reference implementation
    h += l;
    l %= m; h %= m;   // with non-deferred modulo if this is uncommented
  } while(*B);

  return h%m<<16|l%m;
}


#include <stdio.h>
//#include <zlib.h>
#include <string.h>
#include <assert.h>
#include <string>   // useful for the memset-style constructors that repeat a character n times


extern "C" {
    unsigned golfed_adler32_amd64(int /*dummy1*/, const char *buf, int /*dummy2*/, unsigned len);
    unsigned adler32arm_golf(const char *buf, unsigned len);
}
#ifdef __amd64__
#define golfed_adler32(buf, len)   golfed_adler32_amd64(1234, buf, 1234, len)
#elif  __arm__
#define golfed_adler32(buf, len)   adler32arm_golf(buf, len)
#else
#error "no architecture"
#endif

static void test_adler(const char *str)
{
    unsigned len = strlen(str);
//    unsigned zlib = zlib_adler(len, str);
    unsigned reference = adler32_simple((const uint8_t*)str);
    unsigned golfed = golfed_adler32(str, len);

    printf("%s: c:%u asm:%u\n", str, reference, golfed);
    assert(reference == golfed);
}

// main() to call test_adler() unchanged from my amd64 answer, except that the comments about length limits don't apply

3

Fungsi kode mesin x86 16bit: 32 byte menggunakan konvensi pemanggilan kustom

Args dalam register, dan tidak melestarikan regs selain bp (dan sp).

Dalam kode 16bit, kami mengembalikan nilai 32bit dalam dx:axpasangan register. Ini berarti kita tidak perlu menghabiskan petunjuk setiap penggabungan highdan lowmenjadi eax. (Ini akan menghemat byte dalam kode 32 dan 64 bit, tetapi kami hanya bisa membenarkan pembongkaran pekerjaan ini ke pemanggil dalam kode 16bit.)

Sumber dan driver tes yang dikomentari pada github (untuk x86 16, 32, dan 64bit, dan ARM).

### const char *buf in SI,  uint16_t len in CX
## returns in dx:ax
## also clobbers bx and di.
00000100 <adler32_x16_v6>:
 100:   31 c0                   xor    ax,ax         # set up for lods
 102:   99                      cwd                  # dx= high=0
 103:   bf 01 00                mov    di,0x1        # di= low=0
 106:   bb f1 ff                mov    bx,0xfff1     # bx= m
00000109 <adler32_x16_v6.byteloop>:
 109:   ac                      lods
 10a:   01 c7                   add    di,ax         # low+=buf[i]. modulo-reduce on carry, or on low>=m
 10c:   72 04                   jc     112 <adler32_x16_v6.carry_low>
 10e:   39 df                   cmp    di,bx
 110:   72 02                   jb     114 <adler32_x16_v6.low_mod_m_done>
00000112 <adler32_x16_v6.carry_low>:
 112:   29 df                   sub    di,bx
00000114 <adler32_x16_v6.low_mod_m_done>:
 114:   01 fa                   add    dx,di         # high+=low
 116:   0f 92 d0                setb   al            # store the carry to set up a 32bit dividend.
 119:   92                      xchg   dx,ax
 11a:   f7 f3                   div    bx            # high (including carry) %= m, in dx.  ax=0 or 1 (so we're set for lods next iteration)                                                         
 11c:   e2 eb                   loop   109 <adler32_x16_v6.byteloop>
 11e:   97                      xchg   di,ax         # 
 11f:   c3                      ret    
00000120 <adler32_x16_v6_end>:

0x120 - 0x100 = 32 byte

Diuji dengan merakit kode yang sama untuk mode 32bit, jadi saya bisa menyebutnya (dengan fungsi pembungkus) dari C yang dikompilasi dengan -m32. Bagi saya, mode 16bit agak menarik, panggilan sistem DOS tidak. Semua instruksi memiliki operan eksplisit, kecuali loopdan lodsb, jadi perakitan untuk mode 32bit menggunakan awalan ukuran operan. Instruksi yang sama, pengkodean yang berbeda. Tetapi lodsbdalam mode 32bit akan digunakan[esi] , jadi versi untuk-pengujian ini bekerja dengan pointer 32-bit (karena kita tidak melakukan kenaikan-perbandingan alamat atau matematika / pointer).

Tidak ada ketidakcocokan. Harness pengujian saya mencetak pesan jika ada ketidakcocokan.

$ yasm -felf32 -Worphan-labels -gdwarf2 adler32-x86-16.asm -o adler32-x86-16+32.o &&
   g++ -DTEST_16BIT -m32 -std=gnu++11 -O1 -g -Wall -Wextra -o test-adler32-x16  adler32-x86-16+32.o  test-adler32.cpp -lz &&
   ./test-adler32-x16
Eagles are great! (len=17): zlib:0x36c405fe  c:0x36c405fe golfed:0x36c405fe
Programming Puzzles & Code Golf (len=31): zlib:0xbac00b2a  c:0xbac00b2a golfed:0xbac00b2a
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=32): zlib:0x040f0fc1  c:0x040f0fc1 golfed:0x040f0fc1
?????????????????????????????????????????????????? (len=1040): zlib:0x82000000  c:0x82000000 golfed:0x82000000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=4096): zlib:0xb169e06a  c:0xb169e06a golfed:0xb169e06a
(0xFF repeating) (len=4096): zlib:0x8161f0e2  c:0x8161f0e2 golfed:0x8161f0e2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=5837): zlib:0x5d2a398c  c:0x5d2a398c golfed:0x5d2a398c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=5838): zlib:0x97343a0a  c:0x97343a0a golfed:0x97343a0a
(0xFF repeating) (len=9999): zlib:0xcae9ea2c  c:0xcae9ea2c golfed:0xcae9ea2c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=65535): zlib:0x33bc06e5  c:0x33bc06e5 golfed:0x33bc06e5

Dengan register 16bit, kami tidak dapat menunda pengurangan modulo sampai setelah loop. Ada perbedaan yang menarik antara 16bit dan ukuran operan lainnya: m = 65521( 0xFFF1) lebih dari setengah 65536. Mengurangkan mpada carry menjaga nilainya di bawah 2 * m, bahkan jika high=0xFFF0 + 0xFFF0. Setelah loop, bandingkan dan kurangi akan melakukan trik, bukan adiv .

Saya datang dengan teknik baru untuk mengurangi register modulo setelah add yang dapat menghasilkan barang bawaan . Alih-alih membidik bagian atas input untuk div, gunakan setc dluntuk membuat dividen 32bit yang menahan hasil tambah yang tidak terpotong ( dhsudah nol). (div Apakah 32b / 16b => 16bit divisi.)

setcc(3 byte) diperkenalkan dengan 386. Untuk menjalankan ini pada 286 atau sebelumnya, yang terbaik yang saya buat menggunakan instruksi tidak berdokumen salc(atur AL dari carry) . Ini adalah opcode satu byte untuk sbb al,al, jadi kita bisa menggunakan salc/ neg alsebelum melakukan xchg ax, dx(yang kita perlukan). Tanpasalc , ada urutan 4B: sbb dx,dx/ neg dx. Kami tidak dapat menggunakan 3B sbb dx,dx/ inc dx, karena itu akan ditiru setncdaripada setc.


Saya mencoba menggunakan ukuran operan 32bit alih alih menangani carry, tetapi bukan hanya addinstruksi yang memerlukan awalan ukuran operan. Instruksi pengaturan konstanta dan seterusnya juga membutuhkan awalan ukuran operan, sehingga akhirnya tidak menjadi yang terkecil.



2

Perl 5, 43 byte

42 byte, ditambah 1 untuk -aE bukan-e

Input adalah bilangan bulat desimal, dipisahkan oleh spasi.

map$h+=$.+=$_,@F;say$.%65521+$h%65521*4**8

Ujung topiku untuk Sp3000 , dari siapa saya mengambil ide untuk jawaban ini.

Bagaimana itu bekerja:

  1. Karena -a, $. mulai dari 1 dan @Fmerupakan array input. $hmulai dari 0. $_digunakan olehmap sebagai placeholder untuk setiap elemen array.
  2. map$h+=$.+=$_,@Fberarti bahwa untuk setiap elemen dalam @Fkita menambahkan elemen itu untuk $.dan kemudian menambahkan $.ke $h.
  3. Kemudian kita melakukan aritmatika modular $.%65521+$h%65521*4**8(yaitu, ($. % 65521) + ( ($h % 65521) * (4**8) )dan say(mencetak) hasilnya.

1

Faktor, 112 109 103 byte

Sekarang , ini adalah terjemahan harfiah dari algoritma dalam pertanyaan ... sekarang saya benar-benar membuatnya, Anda tahu, benar.

[ [ sum 1 + ] [ [ dup length [1,b] reverse v. ] [ length ] bi + ] bi [ 65521 mod ] bi@ 16 shift bitor ]

Tidak Disatukan:

: adler-32 ( seq -- n )
  [ sum 1 + ] 
  [ 
    [ dup length [1,b] reverse v. ] 
    [ length ] bi + 
  ] bi 
  [ 65521 mod ] bi@ 
  16 shift bitor 
  ;

Mengharapkan urutan angka atau string apa pun (tidak banyak perbedaan, meskipun secara teknis tidak sama).

Saya tidak tahu bagaimana ini akan bekerja untuk batas yang diberikan pada versi Factor yang dikompilasi dengan ukuran kata 32-bit, tetapi pada mesin 2.2GHz 6GB 64-bit saya:

IN: scratchpad 1040 63 <array>

--- Data stack:
{ 63 63 63 63 63 63 63 63 63 63 63 63 63 63 ~1026 more~ }
IN: scratchpad [ adler-32 ] time
Running time: 7.326900000000001e-05 seconds

--- Data stack:
2181038080
IN: scratchpad 10,000 63 <array> 

--- Data stack:
2181038080
{ 63 63 63 63 63 63 63 63 63 63 63 63 63 63 ~9986 more~ }
IN: scratchpad [ adler-32 ] time
Running time: 0.000531669 seconds

1

Ruby, 91 byte

->s{b=s.bytes;z=i=b.size
b.inject(1,:+)%65521+b.map{|e|e*(1+i-=1)}.inject(z,:+)%65521*4**8}

1

Clojure, 109 byte

Berdasarkan solusi @ Mark Adler .

(fn f[s](->> s(reduce #(mapv + %(repeat %2)[0(first %)])[1 0])(map #(rem % 65521))(map *[1 65536])(apply +)))

Tidak disatukan

(fn f [s]
  (->> s
       (reduce #(mapv + % (repeat %2) [0 (first %)]) [1 0])
       (map #(rem % 65521))
       (map * [1 65536])
       (apply +)))

Pemakaian

=> (def f (fn f[s](->> s(reduce #(mapv + %(repeat %2)[0(first %)])[1 0])(map #(rem % 65521))(map *[1 65536])(apply +))))
=> (f [69 97 103 108 101 115 32 97 114 101 32 103 114 101 97 116 33])
918816254
=> (f [80 114 111 103 114 97 109 109 105 110 103 32 80 117 122 122 108 101 115 32 38 32 67 111 100 101 32 71 111 108 102])
3133147946
=> (f (repeat 32 126))
68095937
=> (f (repeat 1040 63))
2181038080
=> (f (repeat 4096 255))
2170679522

1

Javascript (130 Karakter Ber Golf)

Tidak disatukan

function a(b)
{
    c=1
    for(i=0;i<b.length;i++)
    {
        c+=b[i]
    }
    d=c%65521
    f=""
    e=0
    k=""
    for(j=0;j<b.length;j++)
    {
        k+= "+"+b[j]
        f+= "(1"+k+")"
        e= ((eval(f)))
        if(j!=b.length-1){f+="+"}
    }
    g=e%65521
    h=d+65536*g
    console.log(h)
}

Golf

a=b=>{for(c=1,k=f="",y=b.length,i=0;i<y;i++)c+=x=b[i],f+="(1"+(k+="+"+x)+")",i<y-1&&(f+="+");return z=65521,c%z+65536*(eval(f)%z)}

Rekatkan ke Konsol Pengembang dan berikan Array Bytes EG:

[69, 97, 103, 108, 101, 115, 32, 97, 114, 101, 32, 103, 114, 101, 97, 116, 33]

Dan itu akan mengembalikan checksum ke konsol


1

TMP, 55 byte

3a1.3b0.1;4+a>T8%a>xFFF14+b>a8%b>xFFF11~5<b>164|b>a2$b$

Implementasi di Lua dapat ditemukan di sini: http://preview.ccode.gq/projects/TMP.lua


1
Selamat Datang di Programming Puzzles dan Code Golf! Apakah bahasa ini memenuhi definisi kami tentang bahasa pemrograman ?
kucing

@cat, saya percaya memang begitu, tapi saya tidak yakin apakah itu benar-benar mendukung "tuple?"
brianush1

BrainFuck juga tidak, jadi Anda mungkin baik-baik saja. Jika turing lengkap, dapat menemukan bilangan prima dan dapat melakukan hal-hal dasar yang dapat dilakukan bahasa lain (dan dapat), itu akan bekerja :) CSS bukan bahasa pemrograman sendiri dan tidak juga HTML tetapi CSS3 + HTML turing-complete dan dapat menemukan bilangan prima.
kucing

Jadi, boleh saja menggunakan CodeGolf?
brianush1

Saya kira begitu - saya tidak tahu TMP atau Lua, jadi penjelasan tentang kode ini akan sangat membantu (dan akan membuat ini menjadi jawaban yang bagus). : D
cat

1

Python 3.5, 82 byte:

( -1 byte terima kasih kepada Neil ! )

( -1 byte terima kasih kepada mathmandan ! )

( -4 byte terima kasih kepada Dennis ! )

lambda w:((1+sum(w))%65521)+4**8*(sum(1+sum(w[:i+1])for i in range(len(w)))%65521)

lambdaFungsi anonim . Menerima array byte, menerapkan seluruh algoritma ke array, dan menampilkan hasilnya. Berhasil bekerja untuk semua kasus uji. Anda memanggil ini dengan menetapkan variabel ke sana, dan kemudian memanggil variabel itu sama seperti Anda memanggil fungsi normal. Jika Anda menggunakan shell, maka ini seharusnya dihasilkan tanpa fungsi cetak. Namun, jika tidak, maka Anda harus membungkus panggilan fungsi dalam print()fungsi untuk benar-benar melihat output.

Cobalah online! (Ideone)


(E+15) is actually a byte longer than 65536.
Neil

@Neil Thanks for the tip. It's fixed now.
R. Kap

@Sp3000 So? It would matter if they added some bytes, but the fact that they add no bytes rests fine with me.
R. Kap

4**8 is a byte shorter than 65536.
mathmandan

You can save 4 bytes by dropping the brackets around the generator and iterating from 0 to len(w). Another 6 bytes can be saved by exploiting operator precedence.
Dennis

1

Fission, 324 bytes

          /   M
       R_MZ  |S
      D ]    |S
 /?V?\} {}/  |S /    \
R{/A  Z$[/   |S/     {\
  } J{\      |S      ;_
 \^  /       |S   R'~++Y++~'L
 /    /      |S       }Y;
 \  \        ;^/
 /  /         +\+ R'~++A++~'L
 \  <Z________________/
    ;\X       //
              \Y/
               *

Fair warning, the only implementation I've tested this on is my own port of the language to F#. It's not golfed, mainly because I found it easier to have a couple of long runs while my prime constant cooled along the bottom, so I may come back and tweak it.

How does it work?

  • The R'~++Y++~'L block fuses a 256 constant and launches it downwards, setting the mass multiplier of the reactor directly below it.
  • The R'~++A++~'A block fuses another 256 and launches it up towards the reactor above, which fissions the particle into two mass multiples of 65536 mass each, launching them left and right (where the right particle is immediately destroyed by the terminator).
  • The left particle hits another reactor and undergoes fission, splitting into two particles of equal mass heading up and down.
  • The upward travelling power-of-two particle passes through a net-zero mass manipulation, reflects to the left, then sets the mass multiplier of the fusion reactor. This reactor will be how we multiply the H block.
  • The downward travelling particle reflects to the left and sheds mass over the long run, ultimately reaching a mass of 65521 (our large prime).
  • The rotational mirror (Z) at the end of the run causes the particle to duplicate the prime, sending one back to the right where it ultimately sets the stored mass of the fission reactor (^). This is how we'll be applying the modulus operator to the H block.
  • The second copy is reflected back, where it performs an analogous function for the fission reactor (<) we'll be using for the L block.
  • Now that our constants are in place, we engage in shenanigans in the upper left to read our input and generate our two lists. To be honest, I forget how those work, but for the empty string I had to slow down the H block summing particle, which explains the |S "cooling tower".
  • \Y/ fuses the L block (which comes in through the left channel) and the H block (which comes in through the right channel), then slams them into a terminator which sets the exit code to the fused mass.

Unless I'm making a mistake somewhere, this doesn't seem to work with the official interpreter (link). Where could I get your port to F#?
Dennis

@Dennis I'm trying to figure out if the bug is on my end or not, but I can't get the interpreter to work either. I'll see if I can get it working then update my answer if need be.
Andrew Coonce

@Dennis It appears that the online interpreter doesn't handle error code aborts *, which is how I'm returning the output. I'll see if I can find another interpreter to verify the output tomorrow.
Andrew Coonce
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.