ピサノ時代を見つける


20

フィボナッチ数列は、各ウェルエントリは、前の2の合計であり、我々はシーケンスが周期的になるだろう定数によって各用語の剰余を取る場合は、最初の2つのエントリが1である、順序を知っています。たとえば、シーケンスmod 7を計算することにした場合、次のようになります。

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

これの周期は16です。ピサノシーケンスと呼ばれる関連するシーケンスa(n)は、nを法として計算されたときのフィボナッチシーケンスの周期であるように定義されます。

仕事

nフィボナッチ数列modの周期を計算して出力するプログラムまたは関数を作成する必要がありますn。これは、Pisanoシーケンスのn番目の項です。

範囲の整数のみをサポートする必要があります 0 < n < 2^30

これは競争なので、ソースコードのサイズをバイト単位で最小化することを目指してください。

テストケース

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
2 ^ 30に制限すると、すべての中間値が2 ^ 31未満になることが保証されますが、それでもピサノ周期が32ビット符号付き整数に収まることは保証されません。(これがあなたの制限の理由だと思いますか?)ピサノ周期はそれらのnよりもかなり大きくなる可能があります。たとえば、6のピサノ周期は24です。100を超える10の累乗は、nよりも50%大きくなります。
イッツィ

3
ピジョンホールの原則によれば、それf(i),f(i+1)n^2modの値を多くても取ることができますn。したがって、にn制限されると2^30、最大での期間が生成され2^60ます。制限n <= 2^16与えるだろうP(n) <= 2^32
ブースバイ

@boothbyあなたが言っていることを理解しているか、それが私と同じ問題に適切に対処しているのかどうか、私にはよくわかりません。おそらく追加のリンクを使用して、もう少し説明してもらえますか?必要に応じて、気軽にチャットに誘ってください。
Iszi

2
@Isziそれを観察してくださいf(i+2) = f(i+1)+f(i)。そのため、周期をループするマシンの「状態」は、1組の整数modで記述できますn。ほとんどのn^2州があるので、期間は最大n^2です。ああ!ウィキペディアは期間はせいぜいであると主張し6nます。私の些細さを決して気にしないでください。
ブースビー

回答:


11

GolfScript(28 25 24 23文字)

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

入力をstdinで受け取り、stdout(または、さらに処理したい場合はスタック)に残します。

これにより、コーナーケースが正しく処理されます(デモ)。

GolfScriptプログラマーの興味を引く点として、これは、私が試みた他のアプローチよりも実際に短い展開で作成した最初のプログラムだと思います。


7

GolfScript、24文字

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

GolfScript実装の次の反復。2番目のバージョンも1を正しく処理するようになりました。かなり長くなりましたが、誰かがこのバージョンを短くする方法を見つけることができるかもしれません。上記のバージョンをオンラインで試すことができます


これは入力を1正しく処理しますか?
ピーターテイラー

@PeterTaylor Nope、そのコーナーケースをテストしませんでした。ふりだしに戻る。
ハワード

@PeterTaylor新しいコードは入力でも機能しますが1、まだ24文字しかありません。
ハワード

4

パイソン、188の 132 101 95 87文字

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

使用法

$ echo 10 | python pisano.py
60

例えば:

$ 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

追加のゴルフをありがとう、beary605
ESultanik

あなたは再びあなたの文字を数えることができます。あなたの回答の私のカウントはあなたの回答のカウントを下回っています。
-DavidC

@David:空白を数えていますか?私はちょうどダブルチェックにより(catにティンwc -cと私は同じ番号を取得する。
ESultanik

Wolfram Researchが提供するルーチンを使用します。必要な空白を数えると思います。
-DavidC

if k>0 and s[0:k]==s[k:]:breakに変更できますif s and s[:k]==s[k:]:break。また、イテレータを削除し、forループをwhile 1:に変更して、whileループa,b=a,a+bの最後で実行することにより、大幅に削減できます。
-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

編集:bearyとprimoによる提案の実装


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

append実際には、とは異なる機能があり+=ます。しかし、ヒントをありがとう。
スクリーバー

この場合も同じように機能すると思います。
beary605

(n>1)>>(c in a) -> (c in a)<1%n3バイト。そして、私は追記についての不満に同意します。に参照を追加するか、の値でc拡張aするかはc、どちらの方法でもまったく同じです(cとにかく参照をすぐに破棄するため)。
プリモ

ああ、私の間違いは私がa+=c代わりに使用していたことでしたa+=[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

2

PHP- 61 57バイト

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

このスクリプトはを誤って報告2n=1ますが、他のすべての値は正しいです。

サンプルI / 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

1
1<$a.$b=+$a+$a=!$i+++$b%$n+=fgets(STDIN)ああ、それはすぐそこにある操作の開発の順序です。
ラマ氏

1

PowerShell:98

ゴルフコード:

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、コメント付き:

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

ノート:

このスクリプトでの$ nの信頼できる最大制限は正確にはわかりません。$ nが到達する前に$ xがint32をオーバーフローさせる可能性があるため、2 ^ 30未満の可能性があります。それに加えて、システムの$ n = 1e7(2 ^ 23を少し超える)でスクリプトの実行時間が約30秒に達するため、上限を自分でテストしていません。同じ理由で、このスクリプトの範囲を拡張するために、必要に応じて変数をuint32、int64、またはuint64にアップグレードするために必要な追加構文があれば、すぐにテストおよびトラブルシューティングを行うつもりはありません。


サンプル出力:

これを別のforループでラップしました。

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

次に、の$n=$i代わりに設定し=read-host、出力を"$i | $x"に変更して、スクリプトの一般的な信頼性を把握します。出力の一部を次に示します。

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

補足: Pisano Periodsが$ nよりも大幅に短いかどうかはよくわかりません。これは正常ですか、それともスクリプトに問題がありますか?ネバーマインド-5の後、フィボナッチ数がシーケンスの位置よりもはるかに大きくなることを思い出しました。したがって、これは今では完全に理にかなっています。


1

パール、7561、62 + 1 = 63

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

使用法

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

非ゴルフ

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

-nフラグ用に+1バイト。Gabriel Benamyのおかげで13バイト削られました。


1
$n=<>;(-6)を取り除き、-nフラグ(+1)で置き換えることが$nできます$_。その後、すべてのインスタンスをで置き換えることができます。あなたは使用することができ-M5.010、使用することができますされ、自由のためのsay代わりのコマンドをprint(-2)。修飾子whileステートメントは、条件を囲む括弧を必要としません(-2)。の代わりに@{[%h]}/2、カウンターを$a++,前に置き、最後に($m,$k)=置くことができますsay$a-1(-2)。"$m,$k"使用する代わりに$m.$k(-2)。これは、61 + 1 = 62バイト$k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)while!$h{$m.$k}++;say$a-1-nフラグを使用して得られるはずです。
ガブリエルベナミー16

明らかに、私は思っていたほどPerlに精通していません。ヒントをありがとう。
シルヴィオマヨロ16

Perlスレッドでのゴルフヒントには、便利なポインターがたくさんあります!がんばろう!^^
ガブリエルベナミー16

実際、私は間違っていました-の"$m,$k"代わりに$m.$k(+2)が必要ですがwhile!$huntil$h(-1)に変更することで1バイト節約できます。ごめんなさい!
ガブリエルベナミー16

うん?どの入力で$m.$k失敗しますか?それは私の終わりにうまくいくように見えました。
シルヴィオマヨロ16

0

Clojure、102バイト

あまりエキサイティングではありませんが、戻るまで式を繰り返します[1 1](これが常に当てはまることを願っています)。(f 1)に収束するときの特別な処理[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))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.