Tidak cukup berpengetahuan luas dalam Python untuk menjawab ini dalam bahasa yang Anda minta, tetapi dalam C / C ++, mengingat parameter pertanyaan Anda, saya akan mengonversi nol dan yang menjadi bit dan mendorong mereka ke bit paling tidak signifikan dari sebuah uint64_t. Ini akan memungkinkan Anda untuk membandingkan semua 55 bit dalam sekali gerakan - 1 jam.
Sangat cepat, dan semuanya akan sesuai dengan cache on-chip (209.880 byte). Dukungan perangkat keras untuk menggeser semua 55 daftar anggota secara bersamaan hanya tersedia di register CPU. Hal yang sama berlaku untuk membandingkan semua 55 anggota secara bersamaan. Ini memungkinkan pemetaan 1-untuk-1 masalah ke solusi perangkat lunak. (dan menggunakan register 256 bit SIMD / SSE, hingga 256 anggota jika diperlukan). Akibatnya, kode ini segera jelas bagi pembaca.
Anda mungkin dapat mengimplementasikan ini dengan Python, saya hanya tidak tahu cukup baik untuk mengetahui apakah itu mungkin atau bagaimana kinerjanya.
Setelah tidur di atasnya beberapa hal menjadi jelas, dan semuanya menjadi lebih baik.
1.) Sangat mudah untuk memutar daftar yang terhubung secara melingkar menggunakan bit sehingga trik Dali yang sangat pintar tidak diperlukan. Di dalam register 64-bit, penggeseran bit standar akan menyelesaikan rotasi dengan sangat sederhana, dan dalam upaya menjadikan ini lebih ramah Python, dengan menggunakan aritmatika alih-alih bit ops.
2.) Penggeseran bit dapat dilakukan dengan mudah menggunakan membagi dengan 2.
3.) Memeriksa akhir daftar untuk 0 atau 1 dapat dengan mudah dilakukan oleh modulo 2.
4.) "Memindahkan" a 0 ke kepala daftar dari ekor dapat dilakukan dengan membagi dengan 2. Ini karena jika nol benar-benar dipindahkan itu akan membuat bit ke-55 salah, yang sudah dengan tidak melakukan apa-apa sama sekali.
5.) "Memindahkan" 1 ke kepala daftar dari ekor dapat dilakukan dengan membaginya dengan 2 dan menambahkan 18.014.398.509.481.984 - yang merupakan nilai yang dibuat dengan menandai bit ke-55 true dan sisanya salah.
6.) Jika perbandingan jangkar dan terdiri uint64_t BENAR setelah setiap rotasi yang diberikan, istirahat dan kembali BENAR.
Saya akan mengonversi seluruh array daftar ke dalam array uint64_ts tepat di depan untuk menghindari harus melakukan konversi berulang kali.
Setelah menghabiskan beberapa jam mencoba mengoptimalkan kode, mempelajari bahasa rakitan saya bisa mencukur 20% dari runtime. Saya harus menambahkan bahwa kompiler O / S dan MSVC mendapat pembaruan tengah hari kemarin juga. Untuk alasan apa pun, kualitas kode yang dihasilkan oleh kompiler C meningkat secara dramatis setelah pembaruan (15/11/2014). Run-time sekarang ~ 70 jam, 17 nanodetik untuk menyusun dan membandingkan cincin jangkar dengan semua 55 putaran cincin tes dan NxN dari semua cincin terhadap yang lainnya dilakukan dalam 12,5 detik .
Kode ini sangat ketat, kecuali 4 register yang tidak melakukan 99% dari waktu. Bahasa assembly cocok dengan kode C hampir baris untuk baris. Sangat mudah dibaca dan dimengerti. Proyek perakitan yang bagus jika seseorang mengajari mereka sendiri.
Perangkat kerasnya adalah Hazwell i7, MSVC 64-bit, optimisasi penuh.
#include "stdafx.h"
#include "stdafx.h"
#include <string>
#include <memory>
#include <stdio.h>
#include <time.h>
const uint8_t LIST_LENGTH = 55; // uint_8 supports full witdth of SIMD and AVX2
// max left shifts is 32, so must use right shifts to create head_bit
const uint64_t head_bit = (0x8000000000000000 >> (64 - LIST_LENGTH));
const uint64_t CPU_FREQ = 3840000000; // turbo-mode clock freq of my i7 chip
const uint64_t LOOP_KNT = 688275225; // 26235^2 // 1000000000;
// ----------------------------------------------------------------------------
__inline uint8_t is_circular_identical(const uint64_t anchor_ring, uint64_t test_ring)
{
// By trial and error, try to synch 2 circular lists by holding one constant
// and turning the other 0 to LIST_LENGTH positions. Return compare count.
// Return the number of tries which aligned the circularly identical rings,
// where any non-zero value is treated as a bool TRUE. Return a zero/FALSE,
// if all tries failed to find a sequence match.
// If anchor_ring and test_ring are equal to start with, return one.
for (uint8_t i = LIST_LENGTH; i; i--)
{
// This function could be made bool, returning TRUE or FALSE, but
// as a debugging tool, knowing the try_knt that got a match is nice.
if (anchor_ring == test_ring) { // test all 55 list members simultaneously
return (LIST_LENGTH +1) - i;
}
if (test_ring % 2) { // ring's tail is 1 ?
test_ring /= 2; // right-shift 1 bit
// if the ring tail was 1, set head to 1 to simulate wrapping
test_ring += head_bit;
} else { // ring's tail must be 0
test_ring /= 2; // right-shift 1 bit
// if the ring tail was 0, doing nothing leaves head a 0
}
}
// if we got here, they can't be circularly identical
return 0;
}
// ----------------------------------------------------------------------------
int main(void) {
time_t start = clock();
uint64_t anchor, test_ring, i, milliseconds;
uint8_t try_knt;
anchor = 31525197391593472; // bits 55,54,53 set true, all others false
// Anchor right-shifted LIST_LENGTH/2 represents the average search turns
test_ring = anchor >> (1 + (LIST_LENGTH / 2)); // 117440512;
printf("\n\nRunning benchmarks for %llu loops.", LOOP_KNT);
start = clock();
for (i = LOOP_KNT; i; i--) {
try_knt = is_circular_identical(anchor, test_ring);
// The shifting of test_ring below is a test fixture to prevent the
// optimizer from optimizing the loop away and returning instantly
if (i % 2) {
test_ring /= 2;
} else {
test_ring *= 2;
}
}
milliseconds = (uint64_t)(clock() - start);
printf("\nET for is_circular_identical was %f milliseconds."
"\n\tLast try_knt was %u for test_ring list %llu",
(double)milliseconds, try_knt, test_ring);
printf("\nConsuming %7.1f clocks per list.\n",
(double)((milliseconds * (CPU_FREQ / 1000)) / (uint64_t)LOOP_KNT));
getchar();
return 0;
}