El desafío de golf de la CPU GOLF: Prime Partitions

14

Este desafío es el primero de una serie de problemas de que deberían escribirse en la CPU GOLF . Puedes encontrar el siguiente aquí

Una partición de un número, Nes una lista de números que se suman N. Una partición prima es una lista de números primos que se suman N.

Para este desafío, se le da un solo número entero N ≥ 2. Necesita generar la partición primaria más corta posible para N. Si hay varias particiones posibles, puede imprimir cualquiera de ellas.

Ejemplos:

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

Su programa debe estar escrito en la CPU GOLF . Para entrada / salida puede usar STDIO o los registros. La lista puede estar en cualquier orden, y si está usando STDOUT, puede separarse por espacios en blanco o comas (no se necesitan corchetes). Obviamente, codificar las soluciones no está permitido, ni codificar más que los primeros números primos.

Este es un problema de , por lo que gana la respuesta que resuelve los ejemplos anteriores con la menor cantidad de ciclos.

Nathan Merrill
fuente
Tiempo para mí para promover GOLF-C , que ofrece una manera más rápida de ejecutar programas .Golf .. y tal vez a trabajar en ello un poco más
Claudiu
@Claudiu Golf-C sin duda estaría permitido aquí
Nathan Merrill
1
¿Hay un límite de tamaño?
lirtosiast 01 de
Sospecho que las conjeturas de Goldbach y Levy serán útiles aquí ...
2012 Arcampion
@ThomasKwa no, sin límite de tamaño, pero sin primos de codificación rígidos (más allá de la primera pareja)
Nathan Merrill

Respuestas:

1

159,326,251 ciclos

De entrada es n, de salida es r, sy t(ignorando los ceros).

# 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

Casos de prueba:

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$ 
Campeonato 2012
fuente
7

Ciclos totales por ejemplos: 477,918,603

Actualización 1: Actualizado para usar la conjetura de Lemoine .

Actualización 2: Actualizado para usar el Tamiz de Eratóstenes en lugar de encontrar ingenuamente los números primos.

Corre con:

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

Ejemplo de ejecución:

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

Recuento de ciclos, por ejemplo, entrada:

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

Consideramos que los primeros (N+1)*8bytes del montón son una matriz que contiene N+1valores de 64 bits. (Como el montón es de tamaño limitado, esto solo funcionará N < 2^57). El valor de la entrada en i*8indica si ies primo:

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

Cuando hayamos terminado de construir la matriz, se verá así [-1, -1, 3, 5, -1, 7, -1, 11, -1, -1, -1, 13, ...].

Usamos el Tamiz de Eratóstenes para construir la matriz.

A continuación, el programa hace lo siguiente en pseudocódigo:

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

Esto está garantizado para funcionar debido a la conjetura de Lemoine y la conjetura débil de Goldbach . La conjetura de Lemoine aún no se ha probado, pero probablemente sea cierto para números inferiores a 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
fuente
¿Puede imprimir el número de ciclos para los números enumerados en el ejemplo?
Nathan Merrill
@NathanMerrill Hecho.
Tyilo