# 2023q1 Homework3 (quiz3)
contributed by < `ShamrockLee` >
### 測驗 `3`
線性回饋移位暫存器,正如其名,能使用電子電路當中的移位暫存器實現。一列移位暫存器當中,邏輯電平隨時脈朝右方傳遞,並透過對事先選定的幾個暫存器值做抑或運算決定最左方的數值。
對應到 `lfsr` 函式,輸入值為指向 64 位元無號整數的指標,該整數的各個位元即對應到電字電路各個移位暫存器的邏輯電平。以最高位對應上述最左端的暫存器,並以位元右移模擬移位暫存器的行為。
```c=
/* Implementation of LFSR (linear feedback shift register)
* on uint64_t using irreducible polynomial x^64 + x^61 + x^34 + x^9 + 1
* (On 32 bit we could use x^32 + x^22 + x^2 + x^1 + 1)
*/
static void lfsr(uint64_t *up)
{
uint64_t new_bit =
((*up) ^ ((*up) >> 3) ^ ((*up) >> 30) ^ ((*up) >> 55)) & 1u;
/* don't have to map '+1' in polynomial */
*up = ((*up) >> 1) | (new_bit << 63);
/* shift *up by 1 to RIGHT and insert new_bit at "empty" position */
}
```
補全後的程式碼如下,`//` 開頭的註解是我就所理解到的部份補充的。
```c=
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* Implementation of LFSR (linear feedback shift register)
* on uint64_t using irreducible polynomial x^64 + x^61 + x^34 + x^9 + 1
* (On 32 bit we could use x^32 + x^22 + x^2 + x^1 + 1)
*/
static void lfsr(uint64_t *up)
{
uint64_t new_bit =
((*up) ^ ((*up) >> 3) ^ ((*up) >> 30) ^ ((*up) >> 55)) & 1u;
/* don't have to map '+1' in polynomial */
*up = ((*up) >> 1) | (new_bit << 63);
/* shift *up by 1 to RIGHT and insert new_bit at "empty" position */
}
static unsigned int N_BUCKETS;
static unsigned char N_BITS;
static const char log_table_256[256] = {
// Repeat 16 times, delimiter: comma, without trailing delimiter
// It would be more readable to renames as _16(n)
#define _(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3,
3, 3, 3, 3, 3, _(4), _(5), _(5), _(6), _(6), _(6),
_(6), _(7), _(7), _(7), _(7), _(7), _(7), _(7), _(7),
#undef _
};
#undef _
/* ASSUME x >= 1
* returns smallest integer b such that 2^b = 1 << b is >= x
*/
uint64_t log2_64(uint64_t v)
{
unsigned r;
uint64_t t, tt, ttt;
// Leading 32 bits of v.
ttt = v >> 32;
if (ttt) {
// Leading 16 bits of v.
tt = ttt >> 16;
if (tt) {
// Leading 8 bits of v.
t = tt >> 8;
if (t) {
r = 56 + log_table_256[t];
} else {
// Leading 8 bits of v are 0.
r = 48 + log_table_256[tt];
}
} else {
// Leading 24 bits of v.
t = ttt >> 8;
if (t) {
// Leading 16 bits of v are 0.
r = 40 + log_table_256[t];
} else {
// Leading 24 bits of v are 0.
r = 32 + log_table_256[ttt];
}
}
} else {
// Leading 48 bits of v.
tt = v >> 16;
if (tt) {
// Leading 40 bits of v.
t = tt >> 8;
if (t) {
r = 24 + log_table_256[t];
} else {
r = 16 + log_table_256[tt];
}
} else {
// Leading 56 bits of v.
t = v >> 8;
if (t) {
r = 8 + log_table_256[t];
} else {
r = 0 + log_table_256[v];
}
}
}
return r;
}
void set_N_BUCKETS(unsigned int n)
{
N_BUCKETS = n;
}
void set_N_BITS()
{
N_BITS = log2_64(N_BUCKETS);
}
/* n == number of totally available buckets, so buckets = \{0, ...,, n-1\}
* ASSUME n < (1 << 32)
*/
unsigned int bucket_number(uint64_t x)
{
// A bit mask of 1's whose log2 value is the same as N_BUCKETS.
uint64_t mask111 = (1 << (N_BITS + 1)) - 1;
// A bit mask of 1's whose log2 value is less then mask111 by 1.
uint64_t mask011 = (1 << (N_BITS)) - 1; /* one 1 less */
unsigned char leq = ((x & mask111) < N_BUCKETS);
/* leq (less or equal) is 0 or 1. */
// Still trying to understand
return (leq * (x & mask111)) +
((1 - leq) * ((x >> (N_BITS + 1)) & mask011));
/* 'x >> (N_BITS + 1)' : take different set of bits -> better uniformity.
* '... & mask011' guarantees that the result is less or equal N_BUCKETS.
*/
}
void fill_buckets(unsigned int *buckets, unsigned int iterations)
{
uint64_t x = 0x98765421b16b00b5;
unsigned char lfsr_iter = (N_BITS << 1);
for (uint64_t i = 0; i < iterations; i++) {
unsigned int tmp_bucket = bucket_number(x);
*(buckets + tmp_bucket) = *(buckets + tmp_bucket) + 1;
/* 'turn handle' on LFSR lfsr_iteration-times! */
unsigned char ell = 0;
while (ell < lfsr_iter) {
lfsr(&x);
ell++;
}
}
}
void evaluate_buckets(unsigned int *buckets)
{
int i = 0;
while (i < N_BUCKETS) {
printf("%d:%d , ", i, *(buckets + i));
i++;
if (i % 10 == 0)
printf("\n");
}
}
int main()
{
int num_of_buckets = 120; /* an example of some non-power of 2 */
int num_of_iterations = (1 << 20); /* roughly 1 million */
set_N_BUCKETS(num_of_buckets);
set_N_BITS();
unsigned int *buckets = malloc(N_BUCKETS * sizeof(unsigned int));
int i = 0;
while (i < N_BUCKETS) {
*(buckets + i) = 0;
i++;
}
fill_buckets(buckets, num_of_iterations);
evaluate_buckets(buckets);
free(buckets);
return 0;
}
```