Le défi de golf GOLF CPU: Prime Partitions

14

Ce défi est le premier d'une série de problèmes de qui devraient être écrits dans le CPU GOLF . Vous pouvez trouver le suivant ici

Une partition d'un nombre,, Nest une liste de nombres qui s'additionnent N. Une partition principale est une liste de nombres premiers qui s'additionnent N.

Pour ce défi, vous recevez un seul entier N ≥ 2. Vous devez générer la partition principale la plus courte possible pour N. S'il existe plusieurs partitions possibles, vous pouvez imprimer n'importe laquelle d'entre elles.

Exemples:

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

Votre programme doit être écrit en GOLF CPU . Pour les entrées / sorties, vous pouvez utiliser STDIO ou les registres. La liste peut être dans n'importe quel ordre, et si vous utilisez STDOUT, elle peut être séparée par des espaces ou des virgules (aucun crochet nécessaire). De toute évidence, le codage en dur des solutions n'est pas autorisé, ni le codage en dur plus que les premiers nombres premiers.

Il s'agit d'un problème de , donc la réponse qui résout les exemples ci-dessus avec le moins de cycles gagne!

Nathan Merrill
la source
Il est temps pour moi de promouvoir GOLF-C , qui offre un moyen plus rapide d' exécuter des programmes .golf .. et peut-être d'y travailler encore plus
Claudiu
@Claudiu Golf-C serait certainement autorisé ici
Nathan Merrill
1
Y a-t-il une limite de taille?
lirtosiast
Je soupçonne que les conjectures de Goldbach et de Levy seront utiles ici ...
2012rcampion
@ThomasKwa non, pas de limite de taille, mais pas de nombres premiers codés en dur (au-delà du premier couple)
Nathan Merrill

Réponses:

1

159326251 cycles

L' entrée est n, la sortie est r, set t(sans tenir compte des zéros).

# 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$ 
2012rcampion
la source
7

Nombre total de cycles pour les exemples: 477 918 603

Mise à jour 1: mise à jour pour utiliser la conjecture de Lemoine .

Mise à jour 2: mise à jour pour utiliser le tamis d'Ératosthène au lieu de trouver naïvement les nombres premiers.

Courir avec:

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

Exemple d'exécution:

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

Nombre de cycles pour exemple d'entrée:

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

Nous considérons les premiers (N+1)*8octets du tas, comme un tableau contenant N+1des valeurs 64 bits. (Comme le tas est de taille limitée, cela ne fonctionnera que pour N < 2^57). La valeur de l'entrée à i*8indique si ic'est un nombre premier:

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

Lorsque nous aurons terminé de construire le tableau, il ressemblera [-1, -1, 3, 5, -1, 7, -1, 11, -1, -1, -1, 13, ...].

Nous utilisons le tamis d'Eratosthène pour construire le tableau.

Ensuite, le programme fait ce qui suit en 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

Cela est garanti de fonctionner en raison de la conjecture de Lemoine et de la faible conjecture de Goldbach . La conjecture de Lemoine n'a pas encore été prouvée, mais c'est probablement vrai pour les nombres inférieurs à 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
la source
Pouvez-vous imprimer le nombre de cycles pour les nombres répertoriés dans l'exemple?
Nathan Merrill
@NathanMerrill Done.
Tyilo