Regex (ECMAScript flavour), 392 358 328 224 206 165 byte
Teknik-teknik yang perlu ikut bermain untuk mencocokkan angka Fibonacci dengan regex ECMAScript (dalam unary) jauh dari cara terbaik dilakukan dalam kebanyakan rasa regex lainnya. Kurangnya referensi atau rekursi maju / bersarang berarti bahwa tidak mungkin untuk secara langsung menghitung atau menjaga total apa pun yang berjalan. Kurangnya tampilan membuatnya sering menjadi tantangan bahkan untuk memiliki cukup ruang untuk bekerja.
Banyak masalah harus didekati dari perspektif yang sama sekali berbeda, dan tampaknya tidak dapat diatasi sampai kedatangan beberapa wawasan kunci. Ini memaksa Anda untuk menggunakan jaring yang jauh lebih luas dalam menemukan properti matematika mana dari angka-angka yang Anda kerjakan yang mungkin dapat digunakan untuk membuat masalah tertentu dapat dipecahkan.
Pada bulan Maret 2014, inilah yang terjadi untuk angka Fibonacci. Melihat halaman Wikipedia, pada awalnya saya tidak bisa menemukan jalan, meskipun satu properti tertentu tampak sangat menggoda. Kemudian teukon matematik menguraikan metode yang membuatnya cukup jelas akan mungkin dilakukan, menggunakan properti itu bersama dengan yang lain. Dia enggan untuk benar-benar membangun regex. Reaksinya ketika saya melanjutkan dan melakukannya:
Kamu gila! ... Saya pikir Anda mungkin melakukan ini.
Seperti posting ECMAScript regex matematika unary saya yang lain, saya akan memberikan peringatan: Saya sangat merekomendasikan belajar bagaimana menyelesaikan masalah matematika unary di ECMAScript regex. Ini merupakan perjalanan yang menarik bagi saya, dan saya tidak ingin merusaknya bagi siapa pun yang mungkin ingin mencobanya sendiri, terutama mereka yang tertarik pada teori bilangan. Lihat posting itu untuk daftar masalah yang direkomendasikan untuk ditandai dengan spoiler bertanda satu per satu.
Jadi jangan membaca lebih jauh jika Anda tidak ingin beberapa sihir regex unary dimanjakan untuk Anda . Jika Anda ingin mencoba mencari tahu sendiri keajaiban ini, saya sangat menyarankan memulai dengan menyelesaikan beberapa masalah dalam ECMAScript regex sebagaimana diuraikan dalam pos yang ditautkan di atas.
Tantangan yang awalnya saya hadapi: Bilangan bulat positif x adalah angka Fibonacci jika dan hanya jika 5x 2 + 4 dan / atau 5x 2 - 4 adalah kuadrat sempurna. Tetapi tidak ada ruang untuk menghitung ini dalam suatu regex. Satu-satunya tempat kita harus bekerja adalah angka itu sendiri. Kami bahkan tidak memiliki cukup ruang untuk mengalikan dengan 5 atau mengambil kuadrat, apalagi keduanya.
ide teukon tentang bagaimana menyelesaikannya ( awalnya diposting di sini ):
Regex disajikan dengan string bentuk ^x*$
, misalkan z menjadi panjangnya. Periksa apakah z adalah salah satu dari beberapa angka Fibonacci pertama dengan tangan (hingga 21 harus dilakukan). Jika tidak:
- Baca beberapa angka, a <b, sehingga b tidak lebih besar dari 2a.
- Gunakan maju melihat ke depan untuk membangun 2 , ab, dan b 2 .
- Tegaskan bahwa 5a 2 + 4 atau 5a 2 - 4 adalah kuadrat sempurna (jadi a harus F n-1 untuk beberapa n).
- Tegaskan bahwa 5b 2 + 4 atau 5b 2 + 4 adalah kuadrat sempurna (jadi b harus F n ).
- Periksa bahwa z = F 2n + 3 atau z = F 2n + 4 dengan menggunakan yang sebelumnya dibangun a 2 , ab, dan b 2 , dan identitas:
- F 2n-1 = F n 2 + F n-1 2
- F 2n = (2F n-1 + F n ) F n
Singkatnya: identitas ini memungkinkan kita untuk mengurangi masalah memeriksa bahwa angka yang diberikan adalah Fibonacci untuk memeriksa bahwa sepasang angka yang jauh lebih kecil adalah Fibonacci. Aljabar kecil akan menunjukkan bahwa untuk n yang cukup besar (n = 3 seharusnya dilakukan), F 2n + 3 > F n + 5F n 2 + 4 sehingga harus selalu ada ruang yang cukup.
Dan di sini adalah mockup dari algoritma di C yang saya tulis sebagai tes sebelum mengimplementasikannya di regex.
Jadi tanpa basa-basi lagi, inilah regex:
^((?=(x*).*(?=x{4}(x{5}(\2{5}))(?=\3*$)\4+$)(|x{4})(?=xx(x*)(\6x?))\5(x(x*))(?=(\8*)\9+$)(?=\8*$\10)\8*(?=(x\2\9+$))(x*)\12)\7\11(\6\11|\12)|x{0,3}|x{5}|x{8}|x{21})$
Cobalah online!
Dan versi komentar yang dicetak cantik:
^(
(?=
(x*) # \2+1 = potential number for which 5*(\2+1)^2 ± 4
# is a perfect square; this is true iff \2+1 is a Fibonacci
# number. Outside the surrounding lookahead block, \2+1 is
# guaranteed to be the largest number for which this is true
# such that \2 + 5*(\2+1)^2 + 4 fits into the main number.
.*
(?= # tail = (\2+1) * (\2+1) * 5 + 4
x{4}
( # \3 = (\2+1) * 5
x{5}
(\2{5}) # \4 = \2 * 5
)
(?=\3*$)
\4+$
)
(|x{4}) # \5 = parity - determined by whether the index of Fibonacci
# number \2+1 is odd or even
(?=xx (x*)(\6 x?)) # \6 = arithmetic mean of (\2+1) * (\2+1) * 5 and \8 * \8,
# divided by 2
# \7 = the other half, including remainder
\5
# require that the current tail is a perfect square
(x(x*)) # \8 = potential square root, which will be the square root
# outside the surrounding lookahead; \9 = \8-1
(?=(\8*)\9+$) # \10 = must be zero for \8 to be a valid square root
(?=\8*$\10)
\8*
(?=(x\2\9+$)) # \11 = result of multiplying \8 * (\2+1), where \8 is larger
(x*)\12 # \12 = \11 / 2; the remainder will always be the same as it
# is in \7, because \8 is odd iff \2+1 is odd
)
\7\11
(
\6\11
|
\12
)
|
x{0,3}|x{5}|x{8}|x{21} # The Fibonacci numbers 0, 1, 2, 3, 5, 8, 21 cannot be handled
# by our main algorithm, so match them here; note, as it so
# happens the main algorithm does match 13, so that doesn't
# need to be handled here.
)$
Algoritma multiplikasi tidak dijelaskan dalam komentar-komentar itu, tetapi dijelaskan secara singkat dalam paragraf posting regex angka saya yang berlimpah .
Saya mempertahankan enam versi berbeda dari regex Fibonacci: empat ratchet dari panjang terpendek ke kecepatan tercepat dan menggunakan algoritma yang dijelaskan di atas, dan dua lainnya yang menggunakan algoritma yang berbeda, jauh lebih cepat tetapi jauh lebih panjang, yang seperti yang saya temukan sebenarnya dapat kembali indeks Fibonacci sebagai pertandingan (menjelaskan bahwa algoritma di sini berada di luar cakupan posting ini, tetapi dijelaskan dalam Gist diskusi asli ). Saya tidak berpikir saya akan mempertahankan versi regex yang sangat mirip lagi, karena pada saat itu saya sedang melakukan semua pengujian di PCRE dan Perl, tetapi mesin regex saya cukup cepat sehingga masalah kecepatan tidak lagi penting (dan jika konstruk tertentu menyebabkan kemacetan, saya dapat menambahkan pengoptimalan untuk itu) - walaupun saya mungkin akan mempertahankan satu versi tercepat dan satu versi terpendek, jika perbedaannya dalam kecepatan cukup besar.
Versi "mengembalikan indeks Fibonacci minus 1 sebagai kecocokan" (tidak banyak golf):
Cobalah online!
Semua versi ada di github dengan riwayat komit penuh optimasi golf:
regex untuk pencocokan angka Fibonacci - pendek, kecepatan 0.txt (yang terpendek tetapi paling lambat, seperti dalam posting ini)
regex untuk pencocokan angka Fibonacci - pendek, kecepatan 1.txt
regex untuk pencocokan angka Fibonacci - pendek, kecepatan 2.txt
regex untuk pencocokan angka Fibonacci - pendek, kecepatan 3.txt
regex untuk mencocokkan angka Fibonacci - regex tercepat.txt
untuk mencocokkan angka Fibonacci - return index.txt