Tantangan Golf CPU GOLF: Partisi Utama

14

Tantangan ini adalah yang pertama dari serangkaian masalah yang harus ditulis dalam GOLF CPU . Anda dapat menemukan yang berikutnya di sini

Partisi angka N,, adalah daftar angka yang ditambahkan N. Sebuah partisi utama adalah daftar bilangan prima yang menambahkan hingga N.

Untuk tantangan ini, Anda diberi bilangan bulat tunggal N ≥ 2. Anda perlu membuat partisi prime sesingkat mungkin untuk N. Jika ada beberapa kemungkinan partisi, Anda dapat mencetak salah satunya.

Contoh:

9: [2, 7]
12: [5, 7]
95: [89, 3, 3]
337: [337]
1023749: [1023733, 13, 3]
20831531: [20831323, 197, 11]

Program Anda harus ditulis dalam GOLF CPU . Untuk input / output, Anda dapat menggunakan STDIO atau register. Daftar dapat dalam urutan apa pun, dan jika Anda menggunakan STDOUT, dapat dipisahkan dengan spasi putih atau koma (tidak perlu tanda kurung). Jelas, hardcoding solusinya tidak diperbolehkan, juga hardcoding tidak lebih dari beberapa bilangan prima pertama.

Ini adalah masalah , jadi jawaban yang memecahkan contoh di atas dengan jumlah siklus paling sedikit menang!

Nathan Merrill
sumber
Saatnya bagi saya untuk mempromosikan GOLF-C , yang menawarkan cara yang lebih cepat untuk menjalankan program .golf .. dan mungkin mengerjakannya lagi
Claudiu
@Claudiu Golf-C pasti akan diizinkan di sini
Nathan Merrill
1
Apakah ada batasan ukuran?
lirtosiast
Saya menduga dugaan Goldbach dan Levy akan berguna di sini ...
Arcampion
@ThomasKwa tidak, tidak ada batas ukuran, tetapi tidak ada bilangan kode yang sulit (di luar pasangan pertama)
Nathan Merrill

Jawaban:

1

159.326.251 siklus

Input n, output r, sdan t(mengabaikan nol).

# Input in register n
# Outputs in registers r, s, t
# (I use the return value as a debug parameter)

# hardcoded case n=2
cmp c, n, 2
jz skip_n2, c
  mov r, 2
  halt 0
skip_n2:
# hardcoded case n=4
cmp c, n, 4
jz skip_n4, c
  mov r, 2
  mov s, 2
  halt 0
skip_n4:

# Sieve of Eratosthenes
mov i, 1
sieve_loop:
  add i, i, 2
  lb a, i
  jnz sieve_loop, a

  mulu j, k, i, i
  geu c, j, n
  jnz end_sieve_loop, c

  sieve_inner_loop:
    sb j, 1
    add j, j, i
    lequ c, j, n
    jnz sieve_inner_loop, c

  jmp sieve_loop

end_sieve_loop:

lb a, n

# if n is even, skip to search
and c, n, 1
jz search, c

# if n is prime, the partition is simply [n]
jnz not_prime, a
  mov r, n
  halt 1
not_prime:

# if n is odd, check n-2
sub i, n, 2
lb a, i

jnz sub_3, a
# if n-2 is prime, the partition is [2, n-2]
mov r, 2
mov s, i
halt 2

sub_3:
# otherwise the partition is [3] + partition(n-3)
mov t, 3
sub n, n, 3

search:
mov i, 1
sub n, n, 1

search_loop:
  add i, i, 2
  sub n, n, 2
  lb a, i
  jnz search_loop, a
  lb a, n
  jnz search_loop, a
  mov r, i
  mov s, n
  halt 3

Testcases:

robert@unity:~/golf-cpu$ ./assemble.py partition.golf
robert@unity:~/golf-cpu$ ./golf.py -p r,s,t partition.bin n=9
2, 7, 0
Execution terminated after 51 cycles with exit code 2.
robert@unity:~/golf-cpu$ ./golf.py -p r,s,t partition.bin n=12
5, 7, 0
Execution terminated after 77 cycles with exit code 3.
robert@unity:~/golf-cpu$ ./golf.py -p r,s,t partition.bin n=95
3, 89, 3
Execution terminated after 302 cycles with exit code 3.
robert@unity:~/golf-cpu$ ./golf.py -p r,s,t partition.bin n=337
337, 0, 0
Execution terminated after 1122 cycles with exit code 1.
robert@unity:~/golf-cpu$ ./golf.py -p r,s,t partition.bin n=1023749
13, 1023733, 3
Execution terminated after 6654139 cycles with exit code 3.
robert@unity:~/golf-cpu$ ./golf.py -p r,s,t partition.bin n=20831531
229, 20831299, 3
Execution terminated after 152670560 cycles with exit code 3.
robert@unity:~/golf-cpu$ 
2012 Arcampion
sumber
7

Total siklus untuk contoh: 477.918.603

Pembaruan 1: Diperbarui untuk menggunakan dugaan Lemoine .

Pembaruan 2: Diperbarui untuk menggunakan Saringan Eratosthenes alih-alih secara naif menemukan bilangan prima.

Jalankan dengan:

python3 assemble.py 52489-prime-partitions.golf
python3 golf.py 52489-prime-partitions.bin x=<INPUT>

Contoh dijalankan:

$ python3 golf.py 52489-prime-partitions.bin x=10233
5
5
10223
Execution terminated after 194500 cycles with exit code 0.

Hitungan siklus misalnya input:

Input    Cycles
9        191
12       282
95       1,666
337      5,792
1023749  21,429,225
20831531 456,481,447

Kami menganggap (N+1)*8byte pertama heap, menjadi array yang berisi nilai N+164-bit. (Karena tumpukan terbatas dalam ukuran, ini hanya akan berfungsi untuk N < 2^57). Nilai entri pada i*8menunjukkan apakah iprima:

Value Description
-1    Not a prime
0     Unknown
1     The largest prime found
n > 1 This is a prime and the next prime is n

Ketika kita selesai membangun array itu akan terlihat seperti [-1, -1, 3, 5, -1, 7, -1, 11, -1, -1, -1, 13, ...].

Kami menggunakan Saringan Eratosthenes untuk membangun array.

Selanjutnya program melakukan hal berikut dalam pseudo-code:

if is_prime(x):
    print x
else:
    if is_even(x):
        for p in primes:
            if is_prime(x - p):
                print p, x - p
                exit
    else:
        if is_prime(x - 2):
            print 2, x - 2
        else:
            for p in primes:
                if is_prime(x - 2 * p):
                    print p, p, 2 * p
                    exit

Ini dijamin berhasil karena dugaan Lemoine dan dugaan Goldbach yang lemah . Dugaan Lemoine belum terbukti, tetapi mungkin benar untuk angka di bawah 2 ^ 57.

    call build_primes

    mov q, x
    call is_prime

    jnz print_prime, a

    and b, x, 1
    jz find_pair, b

    # Check if x - 2 is a prime
    sub q, x, 2
    call is_prime
    jnz print_prime_odd2, a

# Input: x, b
find_pair:
    mov p, 2
find_pair_loop:
    mov d, p
    jz find_pair_even, b

    add d, d, p

find_pair_even:
    sub q, x, d

    call is_prime
    jnz print_prime2_or_3, a

    shl i, p, 3
    lw p, i
    jmp find_pair_loop

print_prime2_or_3:
    jz print_prime2, b

    mov x, p
    call write_int_ln

print_prime2:
    mov x, p
    call write_int_ln

    mov x, q
    call print_prime

print_prime_odd2:
    mov p, 2
    call print_prime2

print_prime:
    call write_int_ln
    halt 0

# Input: x
# Memory layout: [-1, -1, 3, 5, -1, 7, -1, 11, ...]
# x: max integer
# p: current prime
# y: pointer to last found prime
# i: current integer
build_primes:
    sw 0, -1
    sw 8, -1
    sw 16, 1
    mov y, 16

    mov p, 2

build_primes_outer:
    mulu i, r, p, p
    jnz build_primes_final, r

    geu a, i, x
    jnz build_primes_final, a

build_primes_inner:
    shl m, i, 3
    sw m, -1

    add i, i, p

    geu a, i, x
    jz build_primes_inner, a

build_primes_next:
    inc p
    shl m, p, 3
    lw a, m
    jnz build_primes_next, a

    sw y, p
    mov y, m
    sw y, 1

    jmp build_primes_outer

build_primes_final:
    inc p
    geu a, p, x
    jnz build_primes_ret, a

    shl m, p, 3
    lw a, m
    jnz build_primes_final, a

    sw y, p
    mov y, m
    sw y, 1

    jmp build_primes_final

build_primes_ret:
    ret

# Input: q
# Output: a
is_prime:
    shl m, q, 3
    lw a, m
    neq a, a, -1
    ret a

write_int:
    divu x, m, x, 10
    jz write_int_done, x
    call write_int
write_int_done:
    add m, m, ord("0")
    sw -1, m
    ret

write_int_ln:
    call write_int
    mov m, ord("\n")
    sw -1, m
    ret
Tyilo
sumber
Bisakah Anda mencetak jumlah siklus untuk nomor yang tercantum dalam contoh?
Nathan Merrill
@NathanMerrill Selesai.
Tyilo