Знайдіть період Пісано


20

Послідовність Фібоначчі - це добре відома послідовність, у якій кожен запис є сумою попередніх двох, а перші два записи - 1. Якщо ми будемо приймати модуль кожного члена за константу, послідовність стане періодичною. Наприклад, якби ми вирішили обчислити послідовність моди 7, ми отримали б наступне:

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

Це період 16. Пов'язана послідовність, яка називається послідовністю Pisano , визначається такою, що a(n)є періодом послідовності поля при обчисленні модуля n.

Завдання

Ви повинні написати програму або функцію, яка, коли вона nбуде дана , обчислює та виводить період моду послідовності Фібоначчі n. Це п’ятий термін у послідовності Pisano.

Ви повинні підтримувати лише цілі числа в діапазоні 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, але це все ще не гарантує, що період Pisano поміститься в 32-бітне підписане ціле число. (Я припускаю, що це причина вашого обмеження?) Періоди Pisano можуть бути значно більшими за їх n . Наприклад, Пісано Період 6 становить 24. Повноваження на 10 вище 100 виходять на 50 відсотків більше, ніж n .
Іссі

3
Принцип «Голуби» говорить, що f(i),f(i+1)може приймати максимум n^2значень мод n. Таким чином, nобмежений 2^30обсяг може закінчитися періодом до 2^60. Обмеження n <= 2^16дало б P(n) <= 2^32.
кабіна

@boothby Я не зовсім впевнений, що я розумію, що ти кажеш, або якщо це навіть належним чином вирішує ту саму проблему, що і я. Не могли б ви пояснити трохи далі, можливо, за допомогою додаткових посилань? Сміливо залучайте мене до чату, якщо потрібно.
Іссі

2
@Iszi Зауважте, що f(i+2) = f(i+1)+f(i), таким чином, "стан" циклу машин за період може бути описаний парою цілих чисел 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. Друга версія тепер також обробляє 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:та виконавши a,b=a,a+bв кінці циклу while.
Strigoides

4

Пітон 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

Редагувати: реалізовані пропозиції від ведмедя та прима


85:, a.append(c) -> a+=[c]тоді як цикл можна поставити на одну лінію,((n>1)>>(c in a)) -> (n>1)>>(c in a)
beary605

appendнасправді має інший функціонал, ніж +=. Дякую за поради.
скалер

Я думаю, що це працює так само і в цьому випадку.
beary605

(n>1)>>(c in a) -> (c in a)<1%nза 3 байти. І я погоджуюся з бераєм щодо додатка. Незалежно від того, додаєте ви посилання на cабо продовжуєте aна значення c, це точно так само (як ви негайно знищуєте своє посилання на cбудь-який).
примо

Ну добре, моя помилка полягала в тому, що я використовував a+=cзамістьa+=[c]
скальвер

2

Математика 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;

Цей сценарій буде помилково повідомляти 2 про n=1, але всі інші значення є правильними.

Зразок вводу / виводу, ліворубний ряд, де π (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)}

Безголовка, з коментарями:

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 за допомогою цього сценарію. Це цілком можливо менше 2 ^ 30, оскільки $ x може переповнювати int32, перш ніж $ n потрапить туди. Крім того, я ще не перевіряв верхню межу, тому що час роботи сценарію в моїй системі вже склав близько 30 секунд за $ n = 1e7 (що лише трохи більше 2 ^ 23). З тієї ж причини я не швидко схильний перевіряти та усунути неполадки, будь-який додатковий синтаксис може знадобитися для оновлення змінних до uint32, int64 або uint64 там, де це потрібно для розширення діапазону цього сценарію.


Вибірка зразка:

Я загорнув це в інший цикл:

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

Sidenote: Я не дуже впевнений, наскільки певні періоди Pisano значно коротші, ніж $ n. Це нормально, чи щось не в моєму сценарії? Nevermind - я просто згадав, що після 5 числа Фібоначчі швидко стають набагато більшими, ніж їх місце в послідовності. Отже, зараз це має тотальний сенс.


1

Перл, 75 , 61 , 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

+1 байт для -nпрапора. Поголив 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). Це має вийти $k=1%$_;$a++,($m,$k)=($k,($m+$k)%$_)while!$h{$m.$k}++;say$a-1з -nпрапором, для 61 + 1 = 62 байти.
Габріель Бенамі

Очевидно, що я не такий розумний з Перлом, як думав, що є. Дякую за поради.
Сільвіо Майоло

У Радах для гольфу в нитці Perl дуже багато корисних покажчиків ! Удачі! ^^
Габріель Бенамі

Насправді я помилявся - вам потрібно "$m,$k"замість $m.$k(+2), але ви можете зберегти 1 байт, змінивши while!$hна until$h(-1). Вибачте!
Габріель Бенамі

Гм? Під яким входом не $m.$kвдається? Здавалося, це працює на моєму кінці.
Сільвіо Майоло

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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.