Die GOLF CPU Golf Challenge: Prime Partitions

14

Diese Herausforderung ist das erste einer Reihe von Problemen mit den , die in die GOLF-CPU geschrieben werden sollten . Sie können den nächsten finden hier

Eine Partition einer Zahl Nist eine Liste von Zahlen, die sich zu addieren N. EIN Primpartition ist eine Liste von Primzahlen, die zusammengerechnet werden N.

Für diese Herausforderung erhalten Sie eine einzelne Ganzzahl N ≥ 2 . Sie müssen die kürzest mögliche Prim-Partition für generieren N. Wenn es mehrere mögliche Partitionen gibt, können Sie jede davon drucken.

Beispiele:

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

Ihr Programm sollte in geschrieben sein GOLF-CPU geschrieben sein . Für die Ein- / Ausgabe können Sie entweder STDIO oder die Register verwenden. Die Liste kann in beliebiger Reihenfolge erstellt und bei Verwendung von STDOUT durch Leerzeichen oder Kommas getrennt werden (keine Klammern erforderlich). Offensichtlich ist das Hardcodieren der Lösungen nicht zulässig und auch nicht das Hardcodieren von mehr als den ersten Primzahlen.

Dies ist ein Problem mit den wenigsten , daher gewinnt die Antwort, die die obigen Beispiele mit der geringsten Anzahl von Zyklen löst!

Nathan Merrill
quelle
Zeit für mich zu fördern GOLF-C , die einen schnelleren Weg bietet , um Programme zu laufen .golf .. und vielleicht an die Arbeit auf sie einige mehr
Claudiu
@Claudiu Golf-C wäre hier sicherlich erlaubt
Nathan Merrill
1
Gibt es eine Größenbeschränkung?
Lirtosiast
Ich vermute, die Vermutungen von Goldbach und Levy werden sich hier als nützlich erweisen ...
2012rcampion
@ThomasKwa nein, keine Größenbeschränkung, aber keine harten Kodierungsprimzahlen (über das erste Paar hinaus)
Nathan Merrill

Antworten:

1

159.326.251 Zyklen

Eingegeben wird n, ausgegeben wird r, sund t( unter Vernachlässigung Nullen).

# 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

Testfälle:

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
quelle
7

Gesamtzyklen für Beispiele: 477.918.603

Update 1: Aktualisiert, um Lemoines Vermutung zu verwenden .

Update 2: Aktualisiert, um das Sieb des Eratosthenes zu verwenden, anstatt die Primzahlen naiv zu finden.

Laufen mit:

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

Beispiellauf:

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

Zykluszahl zum Beispiel Eingabe:

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

Wir betrachten die ersten (N+1)*8Bytes des Heaps als ein Array mit N+164-Bit-Werten. (Da der Heap in der Größe begrenzt ist, funktioniert dies nur für N < 2^57). Der Wert des Eintrags bei i*8gibt an , obi es sich um eine Primzahl handelt:

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

Wenn wir fertig sind, wird das Array so aussehen [-1, -1, 3, 5, -1, 7, -1, 11, -1, -1, -1, 13, ...] .

Wir nehmen das Sieb des Eratosthenes , um das Array zu erstellen.

Als nächstes macht das Programm folgendes in Pseudocode:

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

Dies wird aufgrund von Lemoines Vermutung und Goldbachs schwacher Vermutung garantiert funktionieren . Lemoines Vermutung ist noch nicht bewiesen, aber es ist wahrscheinlich wahr für Zahlen unter 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
quelle
Können Sie die Anzahl der Zyklen für die im Beispiel aufgelisteten Zahlen ausdrucken?
Nathan Merrill
@ NathanMerrill Fertig.
Tyilo,