Polar SCL的C語言實現(Lazy Copy)

Part 1.內容回顧

在SCL的C語言實現初級篇中,我們使用的複製方法是全覆蓋的,而實際上,我們真的需要複製的b值與浮點比特a其實並沒有那麼多,而對於一個碼長爲64的4-SCL程序而言,它每次運行就要複製30次路徑(除了兩個分裂的,其他信息位都要複製),如果每次我們都要大範圍複製4次,那麼每次運行的時間消耗就已經比lazy copy(只複製必要的)多了數倍,如果是運行多次,那更是令人頭疼(CPU更疼)。

這次,我們的譯碼對象是碼長64的2-SCL,兩條路徑之間的競爭關係清晰明瞭,更有利於我們對lazy copy方法的講解。

Part 2.複製原理

先上圖,假如我們剛好譯碼至第三位LLR且需要選擇路徑分裂(第3位處於路經篩選、準備分裂的狀態),那麼,哪些值需要複製呢?

LLR我們只需複製前2位;雖然綠色部分的b值已經進行了g運算,但是,待第3、4行LLR值計算完成,開始異或運算求b值時,第二列新的b值會與舊的b值進行異或運算,因此,在複製路徑時,仍需複製那部分b值;而第二列的a值仍未進行g運算,因此,它們要得到保留,而第三列的a值在計算第四位LLR值後,會直接被新的b值覆蓋,它們本身也完成了g運算,因此,不必保留,而第四列的8個a值還要用於g運算,因此需要保留。

然而,遇到下一個例子,要複製、保留的就多一些,下面是譯碼至第5位(第5位處於路經篩選、準備分裂的狀態)的情況:

這時,LLR的複製範圍是前面4位;而第4列的8個a值已經用於g運算,無需複製;第2、3列的a值待執行g運算,需要複製。

至於b值,在我們的一維數組當中,深綠色的b值會取代淺綠色的b值,而同樣,深綠色的b值會在其下方淺紅色的a值變成b值後,繼續進行異或運算,可見,這部分的b值仍有效用,需要複製。

從宏觀看,我們即使計算到如下圖的第20位LLR,但我們的b值仍需保留0~16位的;而a值只需保留沒有使用過的即可;LLR譯碼值也只用複製到當前的位置。

可見,對於不同比特位,它們需要複製的範圍差異較大,我們的初級算法就是將他們全覆蓋,適用於各比特位的路徑複製,但過度浪費複製時間與內存資源。我們需要做的是,適用於全部範圍的比特複製,但儘可能地減少複製。下面,我們就在代碼實戰中講解。

Part 3.代碼實戰

爲直觀的比較lazy copy與初級SCL的區別,本次只在有區別的地方展示程序。

區別1:排序函數sort的範圍有改變

void sort(int tail)
{int i;
if(PM[0]>=PM[1]){path=1;
path_change=0;
}
else {path=0;
path_change=1;
}
for(i=head_a;i<N+N/2;i++)pD[path]->a[i]=pD[path_change]->a[i];
//
for(i=0;i<tail+1;i++)pD[path]->B[i]=pD[path_change]->B[i];
//計算到哪,複製到哪
for(i=clue2;i<head_a;i++)pD[path]->b[i]=pD[path_change]->b[i];
//直接把跨越最大範圍的b值複製,clue2對應64碼長程序中計算範圍最廣的function_back函數,該函數功能不僅只是計算b值,還經過g運算計算a值,因此,a值的複製範圍與這個函數也是息息相關的。
PM[0]=PM[1];
}

區別2:程序的註釋中也提到,a值的範圍左區間head_a取值與function_back函數息息相關:

inline void function_back(int i,int v,int l)
{int u=(int)pow(2.0,v);
if(v==3){
for(int x=i;x<i+4;x++)
{pD[l]->b[x]=pD[l]->b[x]^pD[l]->b[x+4]?1:0;}
}
else if(v==4){
for(int x=i+8;x<i+12;x++)  
pD[l]->b[x]=pD[l]->b[x]^pD[l]->b[x+4];
for(int x=i;x<i+8;x++)
{pD[l]->b[x]=pD[l]->b[x]^pD[l]->b[x+8]?1:0;}
}
else if(v==5){
for(int x=i+24;x<i+28;x++)  
pD[l]->b[x]=pD[l]->b[x]^pD[l]->b[x+4];
for(int x=i+16;x<i+24;x++)
{pD[l]->b[x]=pD[l]->b[x]^pD[l]->b[x+8]?1:0;}
for(int x=i;x<i+16;x++)
{pD[l]->b[x]=pD[l]->b[x]^pD[l]->b[x+16]?1:0;}
}
for(int x=i;x<i+u;x++)
{pD[l]->a[x+2*u]=g(pD[l]->a[x+2*u],pD[l]->a[x+3*u],pD[l]->b[x]);
}
//********************************************************************
if(i>=head_a)head_a=i;
//********************************************************************
int p1=u,p2=0;
for(int j=v;j>0;j--)
{for(int x=i;x<i+p1/2;x++)
{pD[l]->a[x+u+p1/2]=f(pD[l]->a[x+2*p1+p2],pD[l]->a[x+2*p1+p2+p1/2]);}
p2+=p1/2;
p1/=2;
}
} 

head_a是我們改變的地方,爲什麼要加上這個if限制條件呢?咱再上圖:

我們知道,function_back函數會根據參數計算不同的單元,比如從上往下數第2個綠色單元到藍色單元,function_back函數對應的行值i是8,但到了藍色單元到紅色單元的計算,行值i是0,而這兩個計算是交叉的,因此,我們需要將head_a的閾值確定好,只能增大,不能減小,否則會造成多餘的計算,甚至導致錯誤。因此,我們要加上if(i>=head_a)的限制條件。

區別3:2-SCL只需分裂一次,4-SCL分裂兩次,建議大家如果想寫lazy copy的SCL的話,就從2-SCL寫起。

最後,感謝耐心觀看,如有表意不明或者錯誤的地方,歡迎指正。

 

發佈了9 篇原創文章 · 獲贊 14 · 訪問量 4698
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章