Gosper 的序列 迴圈檢測

2021-05-10 01:49:29 字數 3443 閱讀 4963

//

高效程式的奧秘hacker's delight henry s. warren, jr. 著馮速譯

// 第5 章位計數5.4 字尾0 計數

// 假設序列x0, x1, x2, ... 是由xn+1 = f(xn) 定義的。如果f 的值域是有限的,那麼序列必定是迴圈的。

// 給定函式f , 迴圈檢測問題就是找到第乙個重複出現的元素的下標

μ和週期λ.

// 參考:http://home.pipeline.com/~hbaker1/hakmem/flows.html#item132loop detector

// knuth, donald e. the art of computer programming, volume 2, third edition 3.1

節的問題6

#include

"iostream"

#include

"bitset"

#include

"limits"

#include

"time.h"

using

namespace std;

#define

out2(t) coutint>::digits>(t)<

#define

size(t) (numeric_limits::digits)

bool

shr31(int x)

//邏輯右移位

#define

hout(x,y,z)hex_out(x,y,z)

inline

void hex(int x)

inline

void hex(unsigned

__int64 x)

void

hex_out(int x, int y, int z)

intnlz(unsigned

int x)

if ((x >> 24) == 0)

if ((x >> 28) == 0)

if ((x >> 30) == 0)

n = n - (x>>31);

return n; }

intntz(unsigned

int x)

if ((x & 0x000000ff) == 0)

if ((x & 0x0000000f) == 0)

if ((x & 0x00000003) == 0)

return n - (x & 1); }

// 平方取中

intf(int a)

// 這裡分五步論證演算法的正確性:

// 0. f

值域有限,則f 函式是迴圈,參考knuth 的證明

// 1.

設前面存的t 最大位置p, 現在查詢最大位置kmax, 總有p = kmax

//證:先證p 不小於且不大於kmax, p 存放的位置每次最大發生在2^i 處,

//如: 10, 100, 1000, 10000 ...

//設位長w = 8, 則1000b 處是交界, ntz(1000b) = 3; kmax = 8-1 - nlz(1000b) = 7 - 4 = 3; 若i < 1000b, kmax <= p

//若i > 1111b , 如i = 10000b, 則p = 4, kmax = 8-1 - nlz(10000b) = 4, kmax = p, 即kmax 隨p 更新 //

又p 取所有位置的最大位置所以總有p = kmax, 不會造成訪問越界,也不會造成訪問遺漏.

// 2. t

陣列有些元素總會被後來的元素覆蓋, 但個別元素在乙個週期內不會被覆蓋.如果存在這種元素(稱為異元素), //

則總能在第二個週期

λ中檢測到迴圈 //

證:如奇數,由於ntz(奇數) = 0, 前乙個奇數總被後乙個奇數覆蓋 //

若偶數,是不是在乙個週期

λ內有偶數不被覆蓋,且不覆蓋別的偶數呢?這一點很重要, 設這種偶數為異元素 //

因為被覆蓋的元素在第二個週期都會反過來覆蓋先前覆蓋它的元素,

//而到第二個週期

λ檢測中,這種異元素不會被反覆蓋,當再一次走到這個值時,就可以檢測到相同,

//所以總能在第二個週期

λ中檢測到迴圈

// 3.

這種異元素總是存在的 //

證:舉例

λ= 10110101b, 從μ

位置開始迴圈, 如果

μ= 0,

則10000000b 位置為異元素, 因為ntz(10000000b)

//是i < 11111111b 中最大的了, 如果

μ= 01001011b,μ+

λ= 100000000b

這個元素獨一無二的, //

在下乙個週期內μ+

λ+ λ< 1000000000b,

不可能有更大的p, 又p 先於kmax 更新,所以在乙個週期內 //

這種獨一無二的元素總是存在的

// 4.

對於週期λ和

μ的求解也就迎刃而解了,可參考item 132 和下面的程式

// 找出序列 的週期 λ (lambda) 和 開始位置 μ 的上下界 mu_l , mu_u

void

ld_gosper(int (*f)(int), int x0, int *mu_l, int *mu_u, int *lambda)

t[ntz(n+1)] = xn;

// no match.}

l: // compute m = max.

m = ((((n >> k) - 1) | 1) << k) - 1;

*lambda = n - m;

lgl = 31 - nlz(*lambda - 1);

// ceil(log2 lambda) - 1

*mu_u = m;

// upper bound on mu.

*mu_l = m - __max(1, 1 << lgl) + 1;

// lower bound on mu.}

void

test1();

void

main()

void

test2()

void

test1()

if (j >= 0x7fff) break; }

ld_gosper(p, q, mu_l, mu_u, lambda);

cout << (*mu_l) << " "

<< (*mu_u) << " "

<< (*lambda) << endl << endl;

x0 = q;

for (int i = 0; i < 50; i++)

delete mu_l; delete mu_u; delete lambda; }

迴圈序列的元素

當我們要實現迴圈乙個序列的元素,提取符合條件的資料時,我使用foreach迴圈序列裡面的元素,即這樣 listli new list foreach var i in correspondent else 但當迴圈到第二次時,會報如下的錯誤 現在,我使用for迴圈序列的元素,具體 如下 list l...

python for迴圈迭代序列

1.迭代字串 for ch in name print ch 當迭代字串時,迭代變數只會包含乙個字元 長度為 1 的字串 但這並不常用。在字串裡中查詢字元時,往往使用 in 來測試成員關係,或者使用 string 模組中的函式以及字元 串方法來檢查子字串.2.列表 namelist walter n...

序列檢測器

序列檢測器是在數字碼流中檢測特定序列,利用同步狀態機的方式可以較容易的實現。比如設計乙個檢測序列為10010的檢測器。st1 確定狀態機的狀態數亮 st2 確定每個狀態下的變數的值 st3 狀態之間切換的條件 st4 觸發狀態機的條件 module xulie x,z,clk,rst input x...