Trouver la période Pisano

20

La séquence de Fibonacci est une séquence bien connue dans laquelle chaque entrée est la somme des deux précédentes et les deux premières entrées sont 1. Si nous prenons le modulo de chaque terme par une constante, la séquence deviendra périodique. Par exemple, si nous décidions de calculer la séquence mod 7, nous obtiendrions ce qui suit:

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

Celui-ci a une période de 16. Une séquence apparentée, appelée la séquence de Pisano , est définie telle que a(n)c'est la période de la séquence des fibonacci lorsqu'elle est calculée modulo n.

Tâche

Vous devrez écrire un programme ou une fonction qui, une fois donné n, calculera et affichera la période du mod de séquence de Fibonacci n. C'est le nième terme de la séquence de Pisano.

Vous ne devez prendre en charge que des entiers sur la plage 0 < n < 2^30

Il s'agit d'une compétition de , vous devez donc viser à minimiser la taille de votre code source telle que notée par octets.

Cas de 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
boîte en carton
la source
3
La limitation à 2 ^ 30 peut garantir que toutes les valeurs intermédiaires sont inférieures à 2 ^ 31 mais cela ne garantit toujours pas que la période Pisano s'inscrira dans un entier signé 32 bits. (Je suppose que c'est la raison de votre limitation?) Les périodes Pisano peuvent être significativement plus grandes que leur n . Par exemple, la période Pisano de 6 est de 24. Des puissances de 10 supérieures à 100 sortent 50% plus grandes que n .
Iszi
3
Le principe du pigeonnier indique que f(i),f(i+1)peut prendre au plus des n^2valeurs mod n. Ainsi, nlimité à 2^30pourrait finir par produire une période allant jusqu'à 2^60. Restreindre n <= 2^16donnerait P(n) <= 2^32.
stand
@boothby Je ne suis pas sûr de comprendre ce que vous dites, ou si cela résout même correctement le même problème que moi. Pourriez-vous expliquer un peu plus, peut-être avec des liens supplémentaires? N'hésitez pas à me tirer sur le chat si besoin.
Iszi
2
@Iszi Observez cela f(i+2) = f(i+1)+f(i), ainsi l '«état» d'une machine en boucle sur la période peut être décrit avec une paire d'entiers mod n. Il y a au plus des n^2états, donc la période est au plus n^2. Oh! Wikipedia prétend que la période est tout au plus 6n. Peu importe ma trivialité.
stand
2
oeis.org/A001175
Digital Trauma

Réponses:

11

GolfScript ( 28 25 24 23 caractères)

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

Prend l'entrée dans stdin, la laisse sur stdout (ou sur la pile, si vous souhaitez la traiter plus avant ...)

Cela gère correctement les cas d'angle ( démo ).

En tant que point d'intérêt pour les programmeurs GolfScript, je pense que c'est le premier programme que j'ai écrit avec un dépliant qui est sorti plus court que les autres approches que j'ai essayées.

Peter Taylor
la source
7

GolfScript, 24 caractères

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

Prochaine itération d'une implémentation GolfScript. La deuxième version gère désormais également 1 correctement. C'est devenu assez long mais peut-être que quelqu'un peut trouver un moyen de raccourcir cette version. Vous pouvez essayer la version ci-dessus en ligne .

Howard
la source
Est-ce que cela gère 1correctement l' entrée ?
Peter Taylor
@PeterTaylor Nope, n'a pas testé ce cas d'angle. Retour à la planche à dessin.
Howard
@PeterTaylor Le nouveau code fonctionne également pour la saisie 1- et toujours seulement 24 caractères.
Howard
4

Python, 188 132 101 101 95 87 caractères

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

Usage

$ echo 10 | python pisano.py
60

Par exemple:

$ 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
ESultanik
la source
Merci, beary605 , pour le golf supplémentaire!
ESultanik
Vous voudrez peut-être compter à nouveau vos caractères. Mon décompte de votre réponse est inférieur au décompte de votre réponse.
DavidC
@David: Comptez-vous les espaces blancs? Je viens revérifié (par catTing wc -cet je reçois le même numéro.
ESultanik
J'utilise une routine fournie par Wolfram Research. Il compte l'espace blanc nécessaire, je pense.
DavidC
if k>0 and s[0:k]==s[k:]:breakpeut être changé en if s and s[:k]==s[k:]:break. Vous pouvez également réduire de manière significative en supprimant l'itérateur, en changeant la forboucle while 1:et en effectuant a,b=a,a+bà la fin de la boucle while.
Strigoides
4

Python 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

Edit: Suggestions mises en œuvre par beary et primo

scleaver
la source
85 a.append(c) -> a+=[c]((n>1)>>(c in a)) -> (n>1)>>(c in a)
:,
appenda en fait une fonctionnalité différente de celle +=. Merci pour les conseils.
scleaver
Je pense que cela fonctionne de la même manière dans ce cas.
beary605
(n>1)>>(c in a) -> (c in a)<1%npour 3 octets. Et je suis d'accord avec Beary sur l'appendice. Que vous ajoutiez une référence à cou étendez apar la valeur de c, c'est exactement la même chose dans les deux cas (car vous détruisez immédiatement votre référence de ctoute façon).
primo
Ah ok, mon erreur était que j'utilisais a+=cau lieu dea+=[c]
scleaver
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
DavidC
la source
2

PHP - 61 57 octets

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

Ce script rapportera 2par erreur pour n=1, mais toutes les autres valeurs sont correctes.

Exemple d'E / S, une série tronçable à gauche où π (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
primo
la source
1
1<$a.$b=+$a+$a=!$i+++$b%$n+=fgets(STDIN)Oh mon dieu, c'est un ordre d'exploitation de l'exploitation juste là.
M. Llama
1

PowerShell: 98

Code golf:

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)}

Non golfé, avec commentaires:

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

Remarques:

Je ne sais pas exactement quelle est la limite maximale fiable pour $ n avec ce script. C'est probablement moins de 2 ^ 30, car $ x pourrait déborder un int32 avant que $ n n'y arrive. En plus de cela, je n'ai pas testé la limite supérieure moi-même car les durées d'exécution du script atteignaient déjà environ 30 secondes sur mon système pour $ n = 1e7 (ce qui n'est que légèrement supérieur à 2 ^ 23). Pour la même raison, je ne suis pas rapidement enclin à tester et à dépanner la syntaxe supplémentaire nécessaire pour mettre à niveau les variables vers uint32, int64 ou uint64 lorsque cela est nécessaire afin d'élargir la plage de ce script.


Exemple de sortie:

J'ai enveloppé cela dans une autre boucle for:

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

Définissez ensuite $n=$iau lieu de =read-hostet modifiez la sortie "$i | $x"pour obtenir une idée de la fiabilité générale du script. Voici une partie de la sortie:

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: Je ne sais pas vraiment comment certaines périodes Pisano sont significativement plus courtes que $ n. Est-ce normal ou quelque chose ne va pas avec mon script? Peu importe - je viens de me rappeler qu'après 5, les nombres de Fibonacci deviennent rapidement beaucoup plus grands que leur place dans la séquence. Donc, cela a un sens total maintenant.

Iszi
la source
1

Perl, 75 , 61 , 62 + 1 = 63

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

Usage

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

Non golfé

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

+1 octet pour le -ndrapeau. Rasé de 13 octets grâce à Gabriel Benamy.

Silvio Mayolo
la source
1
Vous pouvez vous débarrasser de $n=<>;(-6) et le remplacer par le -ndrapeau (+1), puis toutes les instances de $npeuvent être remplacées par $_. Vous pouvez utiliser -M5.010gratuitement, ce qui vous permet d'utiliser la saycommande au lieu de print(-2). Les whileinstructions de modification n'ont pas besoin de parenthèses autour de la condition (-2). Au lieu de @{[%h]}/2, vous pouvez avoir un compteur $a++,avant ($m,$k)=et ensuite juste avoir say$a-1à la fin (-2). Au lieu d' "$m,$k"utiliser $m.$k(-2). Cela devrait ressortir $k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)while!$h{$m.$k}++;say$a-1avec l' -nindicateur, pour 61 + 1 = 62 octets.
Gabriel Benamy
De toute évidence, je ne suis pas aussi intelligent avec Perl que je le pensais. Merci pour les conseils.
Silvio Mayolo
Il y a beaucoup de pointeurs utiles dans les Astuces pour jouer au golf en fil Perl ! Bonne chance! ^^
Gabriel Benamy
En fait, je me trompais - vous avez besoin "$m,$k"au lieu de $m.$k, (+2), mais vous pouvez enregistrer 1 octet en passant while!$hà until$h(-1). Pardon!
Gabriel Benamy
Hm? Sous quelle entrée $m.$kéchoue? Cela semblait fonctionner de mon côté.
Silvio Mayolo
0

Clojure, 102 octets

Pas trop excitant, itère la formule jusqu'à ce que nous revenions [1 1](j'espère que c'est toujours le cas). Traitement spécial au (f 1)fur et à mesure qu'il converge [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))
NikoNyrh
la source