Emette un elenco di tutti i numeri razionali


13

Di tutta la matematica, ci saranno sempre alcuni teoremi che vanno oltre ogni buon senso. Uno di questi è il fatto che esistono diverse dimensioni di infinito. Un altro fatto interessante è l'idea che molti infiniti che sembrano avere dimensioni diverse abbiano effettivamente le stesse dimensioni. Esistono tanti numeri pari quanti numeri interi, quanti sono i numeri razionali.

Il concetto generale di questa domanda è di confrontare la bizzarra realtà dell'infinito. In questa sfida, il tuo programma produrrà un elenco che:

  • In qualsiasi momento specifico, avere sempre un numero intero di voci
  • Alla fine contiene (se lasciato funzionare abbastanza a lungo) qualsiasi numero razionale specifico (diverso da zero) esattamente una volta sull'intero elenco
  • Contengono un numero illimitato di slot vuoti (voci nell'elenco che sono inutilmente impostate su 0)
  • Avere una proporzione di slot vuoti che si avvicina a un limite del 100%
  • Per ogni numero intero positivo N, disporre di un numero infinito di posizioni con N slot vuoti consecutivi

La sfida

La tua sfida è quella di scrivere quel programma più breve possibile che produrrà un elenco speciale con le seguenti regole:

  1. Tutte le voci con un indice che non è un numero quadrato devono essere impostate su zero. Quindi, la prima voce sarà diversa da zero, la seconda e la terza saranno zero, la quarta sarà diversa da zero, ecc.
  2. Tutti i numeri razionali saranno sotto forma di una frazione impropria (come 4/5 o 144/13) che è stata semplificata. L'eccezione è zero, che sarà semplicemente 0.
  3. Tutti i numeri razionali (positivi e negativi) dovrebbero eventualmente apparire nell'elenco se il programma è in esecuzione abbastanza a lungo e con memoria sufficiente. Per ogni particolare numero razionale, il tempo richiesto può essere una quantità arbitrariamente grande, ma sempre finita, di tempo.
  4. Se eseguito per un tempo infinito, nessun numero razionale diverso da zero dovrebbe mai apparire due volte.

La Regola 3 consente alcune variazioni, in quanto vi è un numero infinito di diversi possibili output legali.

L'output sarà un flusso di linee. Ogni riga avrà la forma generale di 5: 2/3dove il primo numero è il numero di entrata, quindi seguito dal numero razionale. Nota che 1: 0sarà sempre la prima riga di output.

Esempio di frammento di output:

1: 1/1
2: 0
3: 0
4: 2/1
5: 0
6: 0
7: 0
8: 0
9: -2/1
10: 0
etc...

Regole, regolamenti e note

Questo è il codice golf. Si applicano le regole standard per il golf. Inoltre, a causa della variazione consentita nell'output, devi almeno mostrare perché ritieni che il tuo elenco conterrà tutti i possibili numeri razionali esattamente una volta e che la tua soluzione sia corretta.

EDIT: Poiché i numeri dei numeri primi hanno distratto dalla sfida, la sto cambiando in numeri quadrati. Ciò raggiunge lo stesso scopo e riduce anche le soluzioni.


1
Qual è il punto della regola 1? Vuoi semplicemente che le persone giochino reciprocamente due programmi separati per testare la primalità ed enumerare i razionali?
Peter Taylor,

Mostra come una porzione molto piccola degli interi abbia ancora la stessa cardinalità dell'insieme completo di numeri razionali e consente inoltre alla percentuale di slot vuoti di avvicinarsi (ma non raggiungere mai) il 100%.
PhiNotPi

Suppongo che anche il programma debba essere eseguito in una quantità fissa di memoria, ovvero non si può presumere che la macchina possa sempre allocare di più? Inoltre, è contro le regole usare (diciamo) un C int per l'indice della lista quando sai che ha un intervallo finito? (Anche se il limite esatto può variare con l'implementazione.) È necessaria una qualche forma di bignum?
breadbox,

1
@PhiNotPi, ci sono modi molto più semplici per farlo, ed è una distrazione dalla parte più interessante della domanda.
Peter Taylor,

1
Nota che 1: 0sarà sempre la prima riga di output. - Questo contraddice il tuo esempio e inoltre non ha senso per me.
Wrzlprmft,

Risposte:


6

Haskell, 184 caratteri

main=putStr.unlines$zip[1..](s>>=g)>>=h
s=(1,1):(s>>=f)
f(a,b)=[(a,a+b),(a+b,b)]
g x@(a,b)=[x,(-a,b)]
h(i,(a,b))=(i^2)%(u a++'/':u b):map(%"0")[i^2+1..i*(i+2)]
i%s=u i++": "++s
u=show

Questo fa una prima traversata dell'albero di Calkin-Wilf , producendo tutti i numeri razionali positivi in ​​forma ridotta esattamente una volta. Si alterna quindi tra positivo e negativo per coprire tutti i numeri e i pad razionali diversi da zero con zero tra le voci quadrate.

Output (escluse le righe zero per brevità):

1: 1/1
4: -1/1
9: 1/2
16: -1/2
25: 2/1
36: -2/1
49: 1/3
64: -1/3
81: 3/2
100: -3/2
...

5

Salvia, 103 113 128

Sage può elencare facilmente i razionali! La formattazione per soddisfare i requisiti del programma, come sempre, rovina tutto.

for i,q in enumerate(QQ):
 for j in[(i-1)^2+1..i*i]:print'%d:'%j,[0,'%d/%d'%(q.numer(),q.denom())][j==i*i]

Sage elenca in QQbase alla loro altezza : il valore assoluto massimo del numeratore e denominatore dopo la riduzione GCD.


È possibile eliminare l' x.next()e utilizzare printsolo una volta, come segue, portando il punteggio fino a 124: x=enumerate(QQ) for i,q in x: for j in[(i-1)^2+1..i*i]: print'%d: '%j,'%d/%d'%(q.numer(),q.denom())if j.is_square()else 0. Questo non viene visualizzato correttamente in un commento, ma penso che tu possa capire cosa intendo.
ris.

A proposito, noto che dopo i primi 4 elementi positivi, l'enumerazione di Sage non è la stessa delle altre risposte. Le formule di Calkin-Wilf danno una sequenza in cui il denominatore di un razionale è il numeratore del razionale successivo; ad es. (..., 1/3, 3/2, 2/3, ...), rispetto a Sage (..., 1/3, 3/1, 2/3, ...). Non riesco a trovare alcuna documentazione per l'enumerazione di Sage, per vedere come viene calcolata.
ris.

@res, grazie! Avrei voluto unire le dichiarazioni di stampa, ma ho dimenticato di usare la notazione [x..y]. È bello vedere un altro utente Sage qui!
stand

4

Python, 162

f=lambda n:f(n/2)if n%2 else f(n/2)+f(n/2-1)if n else 1
n=i=1
while 1:
 print'%d:'%i,
 if i-n*n:s=0
 else: n+=1;s='%d/%d'%((-1)**n*f(n/2-1),f(n/2))
 print s
 i+=1

Questo utilizza la ricorsione data in Recounting the Rationals di Calkin & Wilf.


2

Haskell, 55 byte

mapM_ print$join$iterate(>>=(\x->[x+1,1/(1+1/x)]))[1%1]

uscite

1 % 1
2 % 1
1 % 2
3 % 1
2 % 3
3 % 2
1 % 3
4 % 1
...

1% 1 è la radice dell'albero di Calkin-Wilf; l'iterata aggiunge entrambi i figli di ciascun nodo; il join comprime i livelli in un unico elenco.

120 caratteri se aggiungi le importazioni appropriate, 0 e negativi:

import Data.Ratio
import Control.Monad
main=mapM_ print$0:(join(iterate(>>=(\x->[x+1,1/(1+1/x)]))[1%1])>>=(\x->[-x,x]))

uscite

0 % 1
(-1) % 1
1 % 1
(-2) % 1
2 % 1
(-1) % 2
1 % 2
(-3) % 1
3 % 1
(-2) % 3
2 % 3
(-3) % 2
3 % 2
(-1) % 3
1 % 3
(-4) % 1
4 % 1
...

produrre slot vuoti? è di cattivo gusto :( mi avevi nella "lista di tutte le razionali positive"


mapM_ print$fix((1%1:).(>>= \x->[x+1,1/(x+1)]))è di 47 caratteri. da haskellwiki . funziona così com'è, senza alcuna importazione, nel REPL "provalo" di haskell.org (beh, senza la mapM_ printparte ...)
Will Ness,

1

PHP 105 byte

Nota: questo codice deve essere salvato come iso-8859-1 (ansi) per funzionare correttamente. Gli interpreti online che codificano tutti gli input in utf8 per impostazione predefinita (come ideone) genereranno un output errato.

<?for($f=µ;$i++<$j*$j||++$j%2||(--$$f?$$f--:$f^=C);)echo"$i: ",$i==$j*$j?$j%2?$x=++$ö.~Ð.++$µ:"-$x":0,~õ;

Usando l' enumerazione di Georg Cantor (leggermente modificata per valori +/-).

Se si verificano problemi durante l'esecuzione del codice sopra (probabilmente a causa di una quantità eccessiva di messaggi AVVISO), utilizzare invece questo (107 byte):

<?for($f=µ;$i++<$j*$j||++$j%2||(--$$f?$$f--:$f^=C);)echo"$i: ",$i==$j*$j?$j%2?$x=++$ö.'/'.++$µ:"-$x":0,'
';

1
Ottengo errori di runtime con questo codice (che sembra contenere alcuni caratteri strani, ad esempio "$ ö. ~ Ð.").
res

Puoi dimostrare che questa soluzione funziona, diciamo su ideone? Ottengo anche errori: ideone.com/ru1fo
mellamokb

Ideone sembra fuoriuscire quando vengono generati troppi messaggi di AVVISO: sia ~ Ð (uguale a '/') che ~ õ (uguale a "\ n") genereranno un AVVISO ad ogni iterazione. Ovviamente, se non hai AVVISI disattivati, non è un problema. Un incolla con entrambi sostituiti (107 byte): ideone.com/lFUbl
primo

Ho appena notato che l'interprete PHP di Ideone genera un output errato. Se esegui il codice localmente, vedrai che è corretto. Oppure, potresti provarlo con un interprete PHP valido, come il controllo delle prestazioni di Anarchy Golf: golf.shinh.org/checker.html (salvalo su un file e caricalo)
primo

Quando salvo il codice modificato in un file con codifica ANSI, viene eseguito sull'interprete Anarchy Golf. Tuttavia, ora esiste un problema diverso: viola il requisito secondo cui "nessun numero razionale diverso da zero dovrebbe mai apparire due volte" nell'elenco. In effetti, il codice sembra elencare ogni razionale infinitamente molte volte; ad esempio 1/1, 2/2, 3/3, ... sono tutti uguali razionali, e allo stesso modo per 1/2, 2/4, 3/6, ..., ecc.
ris.

0

Ottava, 168 byte

a=b=p=1;do for i=(p-1)^2+1:p^2-1 printf("%d: 0\n",i)end
printf("%d: %d/%d\n",p^2,a,b)
a=-a;if a>0do if b==1 b=a+1;a=1;else a++;b--;end until 1==gcd(a,b)end
p++;until 0

La soluzione non è molto sofisticata, è solo un semplice attraversamento diagonale del "tappeto" di numeri razionali, scartando tutte le frazioni che possono essere semplificate. Dopo un numero positivo a/b, il suo contrario -a/bviene sempre stampato prima che il successivo passi dalla sequenza.

Attraversamento diagonale di tutte le razionali positive

Poiché tutte le frazioni semplici positive verranno stampate e le frazioni con segno opposto a quelle verranno stampate e non è mai possibile che due diverse frazioni semplici abbiano lo stesso valore, ogni numero razionale diverso da zero verrà stampato esattamente una volta.

Degolfed:

a=b=p=1
do
    for i=(p-1)^2+1:p^2-1
        printf("%d: 0\n",i)         # p=2,3,4: 1..3,5..8,10..15
    end
    printf("%d: %d/%d\n", p^2,a,b); # p=2,3,4: 4,9,16
    a=-a;
    if a>0                          # the rule is: after a/b, a>0 output -a/b
        do
            if b==1 b=a+1;a=1; else a++;b--; end
        until 1==gcd(a,b)
    end
    p++;
until 0
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.