Trova il periodo pisano


20

La sequenza di Fibonacci è una sequenza ben nota in cui ogni voce è la somma delle due precedenti e le prime due voci sono 1. Se prendiamo il modulo di ciascun termine da una costante, la sequenza diventerà periodica. Ad esempio, se decidessimo di calcolare la sequenza mod 7, avremmo ottenuto quanto segue:

1 1 2 3 5 1 6 0 6 6 5 4 2 6 1 0 1 1 ...

Questo ha un periodo di 16. Una sequenza correlata, chiamata sequenza di Pisano , è definita in modo tale che a(n)è il periodo della sequenza fibonacci quando calcolato modulo n.

Compito

Dovresti scrivere un programma o una funzione che, una volta dato n, calcolerà ed emetterà il periodo della mod di sequenza di Fibonacci n. Questo è l'ennesimo termine nella sequenza di Pisano.

È necessario supportare solo numeri interi sull'intervallo 0 < n < 2^30

Questa è una competizione di , quindi dovresti mirare a ridurre al minimo le dimensioni del tuo codice sorgente come segnato da byte.

Casi test

1  -> 1
2  -> 3
3  -> 8
4  -> 6
5  -> 20
6  -> 24
7  -> 16
8  -> 12
9  -> 24
10 -> 60
11 -> 10
12 -> 24

3
La limitazione a 2 ^ 30 può garantire che tutti i valori intermedi siano inferiori a 2 ^ 31 ma non garantisce comunque che il Periodo di Pisano si adatti a un numero intero con segno a 32 bit. (Presumo che sia la ragione del tuo limite?) I periodi di Pisano possono essere significativamente più grandi del loro n . Ad esempio, il periodo di Pisano di 6 è 24. I poteri di 10 sopra 100 escono il 50 percento più grandi di n .
Iszi,

3
Il principio di Pigeonhole dice che f(i),f(i+1)può assumere al massimo i n^2valori mod n. Pertanto, nlimitato a 2^30potrebbe finire producendo un periodo fino a 2^60. Limitare n <= 2^16darebbe P(n) <= 2^32.
stand dal

@boothby Non sono del tutto sicuro di aver capito cosa stai dicendo, o se sta affrontando correttamente lo stesso problema. Potresti spiegare un po 'di più, forse con collegamenti aggiuntivi? Sentiti libero di portarmi in chat, se necessario.
Iszi,

2
@Iszi Osserva che f(i+2) = f(i+1)+f(i), quindi, lo 'stato' di un ciclo macchina nel periodo può essere descritto con una coppia di numeri interi mod n. Ci sono al massimo n^2stati, quindi il periodo è al massimo n^2. Oh! Wikipedia afferma che il periodo è al massimo 6n. Non importa la mia banalità.
stand dal

Risposte:


11

GolfScript ( 28 25 24 23 caratteri)

~1.{(2$+}{.@+2$%}/+\-,)

Prende input in stdin, lo lascia su stdout (o nello stack, se si desidera elaborarlo ulteriormente ...)

Questo gestisce correttamente le custodie angolari ( Demo ).

Come punto di interesse per i programmatori GolfScript, penso che questo sia il primo programma che ho scritto con un dispiegamento che in realtà è risultato più breve degli altri approcci che ho provato.


7

GolfScript, 24 caratteri

~:&1.{.2$+&%.2$(|}do](-,

Prossima iterazione di un'implementazione GolfScript. La seconda versione ora gestisce anche 1 correttamente. È diventato piuttosto lungo ma forse qualcuno può trovare un modo per abbreviare questa versione. Puoi provare la versione precedente online .


Questo gestisce l'input 1correttamente?
Peter Taylor,

@PeterTaylor No, non ho testato quel caso d'angolo. Torna al tavolo da disegno.
Howard,

@PeterTaylor Il nuovo codice funziona anche per l'input 1- e ancora solo 24 caratteri.
Howard,

4

Python, 188 132 101 95 87 caratteri

n=input()
s=[]
a=k=0
b=1
while s[:k]!=s[k:]or k<1:s+=[a%n];k=len(s)/2;a,b=b,a+b
print k

uso

$ echo 10 | python pisano.py
60

Per esempio:

$ for i in {1..50}; do; echo $i | python pisano.py; done
1
3
8
6
20
24
16
12
24
60
10
24
28
48
40
24
36
24
18
60
16
30
48
24
100
84
72
48
14
120
30
48
40
36
80
24
76
18
56
60
40
48
88
30
120
48
32
24
112
300

Grazie, beary605 , per il golf aggiuntivo!
ESultanik,

Potresti voler contare di nuovo i tuoi caratteri. Il mio conteggio della tua risposta è inferiore al conteggio della tua risposta.
DavidC,

@ David: stai contando gli spazi bianchi? Ho appena ricontrollato (facendo riferimento cata wc -ce ottengo lo stesso numero.
ESultanik,

Uso una routine fornita da Wolfram Research. Conta lo spazio bianco necessario, credo.
DavidC,

if k>0 and s[0:k]==s[k:]:breakpuò essere modificato in if s and s[:k]==s[k:]:break. Puoi anche ridurre significativamente rimuovendo l'iteratore, cambiando il forloop in while 1:ed eseguendolo a,b=a,a+balla fine del ciclo while.
Strigoides,

4

Pitone 90 85 96 94 90 82

n=input();c=[1,1];a=[]
while(c in a)<1%n:a+=[c];c=[c[1],sum(c)%n]
print len(a)or 1

Modifica: suggerimenti implementati da beary e primo


85 a.append(c) -> a+=[c]((n>1)>>(c in a)) -> (n>1)>>(c in a)
:,

appendin realtà ha una funzionalità diversa rispetto a +=. Grazie per i suggerimenti però.
scleaver

Penso che funzioni allo stesso modo in questo caso.
beary605

(n>1)>>(c in a) -> (c in a)<1%nper 3 byte. E sono d'accordo con Beary sull'appendice. Se aggiungi un riferimento co estendi in abase al valore di c, è esattamente lo stesso in entrambi i modi (poiché distruggi immediatamente il tuo riferimento c).
primo

Ah ok, il mio errore era che stavo usando a+=cinvece dia+=[c]
scleaver il

2

Mathematica 73

p = {1, 0}; j = 0; q = p;
While[j++; s = Mod[Plus @@ p, n]; p = RotateLeft@p; p[[2]] = s; p != q]; j

2

PHP - 61 57 byte

<?for(;1<$a.$b=+$a+$a=!$i+++$b%$n+=fgets(STDIN););echo$i;

Questo script riportare erroneamente 2per n=1, ma tutti gli altri valori sono corretti.

I / O di esempio, una serie troncabile a sinistra in cui π (n) = 2n + 2:

$ echo 3 | php pisano.php
8
$ echo 13 | php pisano.php
28
$ echo 313 | php pisano.php
628
$ echo 3313 | php pisano.php
6628
$ echo 43313 | php pisano.php
86628
$ echo 543313 | php pisano.php
1086628
$ echo 4543313 | php pisano.php
9086628
$ echo 24543313 | php pisano.php
49086628

1
1<$a.$b=+$a+$a=!$i+++$b%$n+=fgets(STDIN)Oddio, questo è un certo tipo di sfruttamento operativo proprio lì.
Mr. Llama,

1

PowerShell: 98

Codice golfizzato:

for($a,$b=0,(1%($n=read-host))){$x++;if($a+$b-eq0-or("$a$b"-eq10)){$x;break}$a,$b=$b,(($a+$b)%$n)}

Ungolfed, con commenti:

for
(
    # Start with $a as zero, and $b as 1%$n.
    # Setting $b like this at the start helps catch the exceptional case where $n=1.
    $a,$b=0,(1%
    (
        # Grab user input for n.
        $n=read-host
    ))
)
{
    # Increasing the counter ($x) and testing for the end of the period at the start ensures proper output for $n=1.
    $x++;

    # Test to see if we've found the end of the Pisano Period.
    if
    (
        # The first part catches $n=1, since $a and $b will both be zero at this point.
        $a+$b-eq0-or
        (
            # A shorter way of testing $a-eq1-and$b-eq0, which is the end of a "normal" Pisano Period.
            "$a$b"-eq10
        )
    )
    {
        # Pisano Period has reached its end. Output $x and get out of the loop.
        $x;break
    }

    # Pisano Period still continues, perform operation to calculate next number.
    # Works pretty much like a Fibonacci sequence, but uses ($a+$b)%$n for the new $b instead.
    # This takes advantage of the fact we don't really need to track the actual Fibonacci numbers, just the Fibonacci pattern of %$n.
    $a,$b=$b,(($a+$b)%$n)
}

# Variable cleanup - not included in golfed code.
rv n,a,b,x

Appunti:

Non sono sicuro di quale sia il limite massimo affidabile per $ n con questo script. Probabilmente è meno di 2 ^ 30, poiché $ x potrebbe probabilmente traboccare un int32 prima che $ n arrivi. Oltre a ciò, non ho testato personalmente il limite superiore perché i tempi di esecuzione dello script hanno già raggiunto circa 30 secondi sul mio sistema per $ n = 1e7 (che è solo un po 'più di 2 ^ 23). Per lo stesso motivo, non sono propenso a testare e risolvere qualsiasi sintassi aggiuntiva necessaria per aggiornare le variabili a uint32, int64 o uint64 dove necessario al fine di espandere l'intervallo di questo script.


Uscita campione:

L'ho avvolto in un altro per loop:

for($i=1;;$i++)

Quindi imposta $n=$iinvece di =read-hoste modifica l'output in "$i | $x"per avere un'idea dell'affidabilità generale dello script. Ecco alcuni dei risultati:

1 | 1
2 | 3
3 | 8
4 | 6
5 | 20
6 | 24
7 | 16
8 | 12
9 | 24
10 | 60
11 | 10
12 | 24
13 | 28
14 | 48
15 | 40
16 | 24
17 | 36
18 | 24
19 | 18
20 | 60

...

9990 | 6840
9991 | 10192
9992 | 624
9993 | 4440
9994 | 1584
9995 | 6660
9996 | 1008
9997 | 1344
9998 | 4998
9999 | 600
10000 | 15000
10001 | 10212
10002 | 3336
10003 | 5712
10004 | 120
10005 | 1680
10006 | 10008
10007 | 20016
10008 | 552
10009 | 3336
10010 | 1680

Sidenote: Non sono davvero sicuro di come alcuni periodi di Pisano siano significativamente più brevi di $ n. È normale o c'è qualcosa che non va nella mia sceneggiatura? Nevermind - Mi sono appena ricordato che, dopo 5, i numeri di Fibonacci diventano rapidamente molto più grandi del loro posto nella sequenza. Quindi, questo ha perfettamente senso ora.


1

Perl, 75 , 61 , 62 + 1 = 63

$k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)until$h{"$m,$k"}++;say$a-1

uso

$ echo 8 | perl -n -M5.010 ./pisano.pl
12

Ungolfed

$k = 1 % $_;
$a++, ($m, $k) = ($k, ($m + $k) % $_) until $h{"$m,$k"}++;
say $a - 1

+1 byte per -nflag. Rasato 13 byte grazie a Gabriel Benamy.


1
Puoi eliminare $n=<>;(-6) e sostituirlo con il -nflag (+1), quindi tutte le istanze di $npossono essere sostituite con $_. È possibile utilizzare -M5.010gratuitamente, che consente di utilizzare il saycomando anziché print(-2). Le whileistruzioni del modificatore non richiedono parentesi attorno alla condizione (-2). Invece di @{[%h]}/2, puoi avere un segnalino $a++,prima ($m,$k)=e poi solo say$a-1alla fine (-2). Invece di "$m,$k"usare $m.$k(-2). Questo dovrebbe venire fuori $k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)while!$h{$m.$k}++;say$a-1con la -nbandiera, per 61 + 1 = 62 byte.
Gabriel Benamy,

Chiaramente non sono intelligente con Perl come pensavo di essere. Grazie per i suggerimenti
Silvio Mayolo,

Ci sono molti consigli utili nei suggerimenti per giocare a golf nel thread Perl ! In bocca al lupo! ^^
Gabriel Benamy,

In realtà, ho sbagliato - devi "$m,$k"invece $m.$k(+2), ma puoi salvare 1 byte cambiando while!$hin until$h(-1). Scusate!
Gabriel Benamy,

Hm? Sotto quale input $m.$kfallisce? Sembrava funzionare dalla mia parte.
Silvio Mayolo,

0

Clojure, 102 byte

Non troppo eccitante, scorre la formula fino a quando non torniamo indietro [1 1](spero che sia sempre così). Gestione speciale di (f 1)come converge a [0 0].

#(if(< % 2)1(+(count(take-while(fn[v](not=[1 1]v))(rest(iterate(fn[[a b]][b(mod(+ a b)%)])[1 1]))))1))
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.