GOLF CPU Golf Challenge: Prime Partitions

14

To wyzwanie jest pierwszym z serii problemów z , które powinny zostać zapisane w procesorze GOLF . Następny znajdziesz tutaj

Partycja numeru, Nto lista liczb, które się sumują N. Prime partycja jest lista liczb pierwszych, które dodają do N.

W przypadku tego wyzwania otrzymujesz jedną liczbę całkowitą N ≥ 2. Musisz wygenerować możliwie najkrótszą partycję główną N. Jeśli istnieje wiele możliwych partycji, możesz wydrukować dowolną z nich.

Przykłady:

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

Twój program powinien być napisany w GOLF CPU . Do wejścia / wyjścia można użyć STDIO lub rejestrów. Lista może być w dowolnej kolejności, a jeśli używasz STDOUT, można ją oddzielić białymi spacjami lub przecinkami (bez nawiasów). Oczywiście, twarde kodowanie rozwiązań nie jest dozwolone, ani też nie jest to więcej niż kilka pierwszych liczb pierwszych.

Jest to problem z , więc wygrywa odpowiedź, która rozwiązuje powyższe przykłady z najmniejszą liczbą cykli!

Nathan Merrill
źródło
Czas, żebym wypromował GOLF-C , który oferuje szybszy sposób uruchamiania programów .golf .. i może jeszcze nad tym popracować
Claudiu
@Claudiu Golf-C z pewnością byłby tu dozwolony
Nathan Merrill
1
Czy istnieje limit rozmiaru?
lirtosiast
Podejrzewam, że
przydadzą się
@ThomasKwa nie, bez limitu rozmiaru, ale bez stałych kodujących liczb pierwszych (poza pierwszą parą)
Nathan Merrill

Odpowiedzi:

1

159 326 251 cykli

Wejściowy n, wyjściowy r, si t(pomijając zer).

# 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

Przypadki testowe:

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 rcampion
źródło
7

Cykle ogółem dla przykładów: 477,918,603

Aktualizacja 1: Zaktualizowano, aby użyć hipotezy Lemoine .

Aktualizacja 2: Zaktualizowano, aby używać Sita Eratostenesa zamiast naiwnego znajdowania liczb pierwszych.

Biegnij z:

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

Przykładowy przebieg:

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

Liczba cykli na przykład dane wejściowe:

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

Pierwsze (N+1)*8bajty stosu uważamy za tablicę zawierającą N+1wartości 64-bitowe. (Ponieważ wielkość sterty jest ograniczona, będzie to działać tylko w przypadku N < 2^57). Wartość wpisu w i*8oznacza, iże liczba pierwsza jest liczbą pierwszą:

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

Kiedy skończymy budować tablicę, będzie to wyglądać [-1, -1, 3, 5, -1, 7, -1, 11, -1, -1, -1, 13, ...].

Używamy Sita Eratostenesa do zbudowania tablicy.

Następnie program wykonuje następujące czynności w pseudokodzie:

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

Gwarantuje to, że zadziała ze względu na hipotezę Lemoine i słabą hipotezę Goldbacha . Hipoteza Lemoine'a nie została jeszcze udowodniona, ale prawdopodobnie dotyczy to liczb poniżej 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
źródło
Czy możesz wydrukować liczbę cykli dla liczb wymienionych w przykładzie?
Nathan Merrill
@NathanMerrill Gotowe.
Tyilo,