---
tags: sysprog2020
---
# [2020q3](http://wiki.csie.ncku.edu.tw/sysprog/schedule) Homework4 (quiz4)
contributed by < `nickchenchj` >
> related links: [2020q3 第 4 週測驗題](https://hackmd.io/@sysprog/2020-quiz4)
## Problem 1
### Task
* Given two integers `x` and `y`, calculate the [Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance).
Below is the implementation of the function that calculates the Hamming distance:
```c=
int hammingDistance(int x, int y) {
return __builtin_popcount(x OP y);
}
```
#### OP = ?
* `(a)` `|`
* `(b)` `&`
* `(c)` `^`
* `(d)` `+`
* `(e)` `-`
### Solution
According to [GCC Built-in Functions](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html), the description of `__builtin_popcount` is as follows:
> Built-in Function: int __builtin_popcount (unsigned int x)
> * Returns the number of 1-bits in x.
* From the return value `_builtin_popcount(x OP y)`, we can deduce that only pairs of bits in `x` and `y` with the same index but different values will become `1` after `x OP y`. For example, if the LSB in `x` is `0` and the LSB in `y` is `1`, the result of `0 OP 1` will become `1`.
| `x` | `y` | `x OP y` |
|:-----------------:|:-----------------:|:---------:|
| ==10==01 01==10== | ==01==01 01==01== | 1100 0011 |
###### Note: 8-bit integer is used for demonstration
* Clearly, OP must be `^`, so the answer to this problem is `(c)` `^`.
:::success
**Answer**
* OP: `^`
:::
---
## Problem 2
### Task
From LeetCode [1483. Kth Ancestor of a Tree Node](https://leetcode.com/problems/kth-ancestor-of-a-tree-node/):
> You are given a tree with n nodes numbered from 0 to n-1 in the form of a parent array where parent[i] is the parent of node i. The root of the tree is node 0.
>
> Implement the function getKthAncestor(int node, int k) to return the k-th ancestor of the given node. If there is no such ancestor, return -1.
>
> The k-th ancestor of a tree node is the k-th node in the path from that node to the root.
#### Example:

* Input:
```json
["TreeAncestor","getKthAncestor","getKthAncestor","getKthAncestor"]
[[7,[-1,0,0,1,1,2,2]],[3,1],[5,2],[6,3]]
```
* Output:
```json
[null,1,0,-1]
```
:::info
:information_source: **Explanation**
* `7`: there are `7` nodes in a tree
* `[-1, 0, 0, 1, 1, 2, 2]`: indicates the parents of each node
* `[3, 1]`: gets the `1st` ancestor of node `3` (expected ancestor: `1`)
* `[5, 2]`: gets the `2nd` ancestor of node `5` (expected ancestor: `0`)
* `[6, 3]`: gets the `3rd` ancestor of node `6` (expected ancestor: `-1`)
:::
* Below is the implementation of this problem:
```c=
#include <stdlib.h>
typedef struct {
AAA;
int max_level;
} TreeAncestor;
TreeAncestor *treeAncestorCreate(int n, int *parent, int parentSize)
{
TreeAncestor *obj = malloc(sizeof(TreeAncestor));
obj->parent = malloc(n * sizeof(int *));
int max_level = 32 - __builtin_clz(n) + 1;
for (int i = 0; i < n; i++) {
obj->parent[i] = malloc(max_level * sizeof(int));
for (int j = 0; j < max_level; j++)
obj->parent[i][j] = -1;
}
for (int i = 0; i < parentSize; i++)
obj->parent[i][0] = parent[i];
for (int j = 1;; j++) {
int quit = 1;
for (int i = 0; i < parentSize; i++) {
obj->parent[i][j] = obj->parent[i][j + BBB] == -1
? -1
: obj->parent[obj->parent[i][j - 1]][j - 1];
if (obj->parent[i][j] != -1) quit = 0;
}
if (quit) break;
}
obj->max_level = max_level - 1;
return obj;
}
int treeAncestorGetKthAncestor(TreeAncestor *obj, int node, int k)
{
int max_level = obj->max_level;
for (int i = 0; i < max_level && node != -1; ++i)
if (k & (CCC))
node = obj->parent[node][i];
return node;
}
void treeAncestorFree(TreeAncestor *obj)
{
for (int i = 0; i < obj->n; i++)
free(obj->parent[i]);
free(obj->parent);
free(obj);
}
```
#### AAA = ?
* `(a)` `int ***parent`
* `(b)` `int **parent`
* `(c)` `int *parent`
#### BBB = ?
* `(a)` `(-2)`
* `(b)` `(-1)`
* `(c)` `0`
* `(d)` `1`
* `(e)` `2`
#### CCC = ?
* `(a)` `1`
* `(b)` `i`
* `(c)` `i >> 1`
* `(d)` `i >> k`
* `(e)` `k << i`
* `(f)` `1 << i`
### Solution
#### AAA
* By observing `obj->parent = malloc(n * sizeof(int *));` in `treeAncestorCreate`, it is obvious that `parent` is a pointer that points to an array of integer pointers.
* As a result, `AAA` must be `int **parent`.
#### BBB
* To figure out what `BBB` is, we need to know how `treeAncestorCreate` works.
* First, `treeAncestorCreate` creates `obj` and initializes it (`n = 7`):
```c=
TreeAncestor *obj = malloc(sizeof(TreeAncestor));
obj->parent = malloc(n * sizeof(int *));
int max_level = 32 - __builtin_clz(n) + 1;
for (int i = 0; i < n; i++) {
obj->parent[i] = malloc(max_level * sizeof(int));
for (int j = 0; j < max_level; j++)
obj->parent[i][j] = -1;
}
```
* `obj` after initialization:
```graphviz
digraph add_entry{
graph [pad="0.5", nodesep="0.4", ranksep="0.8"];
rankdir=LR
splines=polyline
node [shape=record]
parent [
label="obj->parent"
shape=plaintext
]
nodes [
label="{ <n0>n0 }|{ <n1>n1 }|{ <n2>n2 }|{ <n3>n3 }|{ <n4>n4 }|{ <n5>n5 }|{ <n6>n6 }"
]
ancestors_0 [
xlabel="ancestors of n0"
label="{ <head>-1 | -1 | -1 | -1 }"
]
ancestors_1 [
xlabel="ancestors of n1"
label="{ <head>-1 | -1 | -1 | -1 }"
]
ancestors_2 [
xlabel="ancestors of n2"
label="{ <head>-1 | -1 | -1 | -1 }"
]
ancestors_3 [
xlabel="ancestors of n3"
label="{ <head>-1 | -1 | -1 | -1}"
]
ancestors_4 [
xlabel="ancestors of n4"
label="{ <head>-1 | -1 | -1 | -1}"
]
ancestors_5 [
xlabel="ancestors of n5"
label="{ <head>-1 | -1 | -1 | -1}"
]
ancestors_6 [
xlabel="ancestors of n6"
label="{ <head>-1 | -1 | -1 | -1}"
]
parent -> nodes:n0:w
nodes:n0:e -> ancestors_0:head:w
nodes:n1:e -> ancestors_1:head:w
nodes:n2:e -> ancestors_2:head:w
nodes:n3:e -> ancestors_3:head:w
nodes:n4:e -> ancestors_4:head:w
nodes:n5:e -> ancestors_5:head:w
nodes:n6:e -> ancestors_6:head:w
}
```
* Next, `treeAncestorCreate` stores the parents of each node in `obj->parent[i][0]` (`parentSize = 7`):
```c=
for (int i = 0; i < parentSize; i++)
obj->parent[i][0] = parent[i];
```
* `obj` after storing parents of each node:
```graphviz
digraph add_entry{
graph [pad="0.5", nodesep="0.4", ranksep="0.8"];
rankdir=LR
splines=polyline
node [shape=record]
parent [
label="obj->parent"
shape=plaintext
]
nodes [
label="{ <n0>n0 }|{ <n1>n1 }|{ <n2>n2 }|{ <n3>n3 }|{ <n4>n4 }|{ <n5>n5 }|{ <n6>n6 }"
]
ancestors_0 [
xlabel="ancestors of n0"
label="{ <head>-1 | -1 | -1 | -1 }"
]
ancestors_1 [
xlabel="ancestors of n1"
label="{ <head>0 | -1 | -1 | -1 }"
]
ancestors_2 [
xlabel="ancestors of n2"
label="{ <head>0 | -1 | -1 | -1 }"
]
ancestors_3 [
xlabel="ancestors of n3"
label="{ <head>1 | -1 | -1 | -1}"
]
ancestors_4 [
xlabel="ancestors of n4"
label="{ <head>1 | -1 | -1 | -1}"
]
ancestors_5 [
xlabel="ancestors of n5"
label="{ <head>2 | -1 | -1 | -1}"
]
ancestors_6 [
xlabel="ancestors of n6"
label="{ <head>2 | -1 | -1 | -1}"
]
parent -> nodes:n0:w
nodes:n0:e -> ancestors_0:head:w
nodes:n1:e -> ancestors_1:head:w
nodes:n2:e -> ancestors_2:head:w
nodes:n3:e -> ancestors_3:head:w
nodes:n4:e -> ancestors_4:head:w
nodes:n5:e -> ancestors_5:head:w
nodes:n6:e -> ancestors_6:head:w
}
```
* Then, update grandparents of each node, great-grandparents of each node and so on:
```c=
for (int j = 1;; j++) {
int quit = 1;
for (int i = 0; i < parentSize; i++) {
obj->parent[i][j] = obj->parent[i][j + BBB] == -1
? -1
: obj->parent[obj->parent[i][j - 1]][j - 1];
if (obj->parent[i][j] != -1) quit = 0;
}
if (quit) break;
}
```
* To find the grandparent of a node, simply find the parent's parent.
* Take ancestors of `n3` for example, say we want to find its grandparent:
* ancestors of `n3` (original): `{1, -1, -1, -1}`
* parent of `n3` is `n1` (at `index = 0`)
* ancestors of `n1`: `{0, -1, -1, -1}`
* we know that the grandparent of `n3` is the parent of `n1`, which is `n0` (at `index = 0`) in this case
* update grandparent of `n3` (at `index = 1`) from `-1` to `0`
* ancestors of `n3` (updated): `{1, 0, -1, -1}`
* From the example above, we can see that the system needs to check if the parent of a node exists before the system carries on finding grandparent of the node.
* Note that the parent node is stored in the element **before** (`current_index - 1`) the element which stores the grandparent node (index of parent: `0`, index of grandparent: `1`).
* Therefore, `BBB` is `(-1)`.
* `obj` (complete):
```graphviz
digraph add_entry{
graph [pad="0.5", nodesep="0.4", ranksep="0.8"];
rankdir=LR
splines=polyline
node [shape=record]
parent [
label="obj->parent"
shape=plaintext
]
nodes [
label="{ <n0>n0 }|{ <n1>n1 }|{ <n2>n2 }|{ <n3>n3 }|{ <n4>n4 }|{ <n5>n5 }|{ <n6>n6 }"
]
ancestors_0 [
xlabel="ancestors of n0"
label="{ <head>-1 | -1 | -1 | -1 }"
]
ancestors_1 [
xlabel="ancestors of n1"
label="{ <head>0 | -1 | -1 | -1 }"
]
ancestors_2 [
xlabel="ancestors of n2"
label="{ <head>0 | -1 | -1 | -1 }"
]
ancestors_3 [
xlabel="ancestors of n3"
label="{ <head>1 | 0 | -1 | -1}"
]
ancestors_4 [
xlabel="ancestors of n4"
label="{ <head>1 | 0 | -1 | -1}"
]
ancestors_5 [
xlabel="ancestors of n5"
label="{ <head>2 | 1 | -1 | -1}"
]
ancestors_6 [
xlabel="ancestors of n6"
label="{ <head>2 | 1 | -1 | -1}"
]
parent -> nodes:n0:w
nodes:n0:e -> ancestors_0:head:w
nodes:n1:e -> ancestors_1:head:w
nodes:n2:e -> ancestors_2:head:w
nodes:n3:e -> ancestors_3:head:w
nodes:n4:e -> ancestors_4:head:w
nodes:n5:e -> ancestors_5:head:w
nodes:n6:e -> ancestors_6:head:w
}
```
#### CCC
* code snippet of `treeAncestorGetKthAncestor`:
```c=
int treeAncestorGetKthAncestor(TreeAncestor *obj, int node, int k)
{
int max_level = obj->max_level;
for (int i = 0; i < max_level && node != -1; ++i)
if (k & (CCC))
node = obj->parent[node][i];
return node;
}
```
:::success
**Answers**
* AAA: `int **parent`
* BBB: `(-1)`
* CCC: `1 << i`
:::
---
## Problem 3
### Task
* Given a number `n`, write a function that counts from `1` to `n`.
* if the current number is a multiple of 3, print out `Fizz`
* if the number is a multiple of 5, print out `Buzz`
* if the number is a multiple of 15, print out `FizzBuzz`
* else, print out the number
* Below is the implementation of the [FizzBuzz](https://en.wikipedia.org/wiki/Fizz_buzz) problem:
```c=
#define MSG_LEN 8
static inline bool is_divisible(uint32_t n, uint64_t M) {
return n * M <= M - 1;
}
static uint64_t M3 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 3 + 1;
static uint64_t M5 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 5 + 1;
int main(int argc, char *argv[]) {
for (size_t i = 1; i <= 100; i++) {
uint8_t div3 = is_divisible(i, M3);
uint8_t div5 = is_divisible(i, M5);
unsigned int length = (2 << div3) << div5;
char fmt[MSG_LEN + 1];
strncpy(fmt, &"FizzBuzz%u"[(MSG_LEN >> KK1) >> (KK2 << KK3)], length);
fmt[length] = '\0';
printf(fmt, i);
printf("\n");
}
return 0;
}
```
#### KK1 = ?
* `(a)` `div5`
* `(b)` `div3`
* `(c)` `2`
* `(d)` `1`
#### KK2 = ?
* `(a)` `0`
* `(b)` `1`
* `(c)` `2`
* `(d)` `div3`
* `(e)` `div5`
#### KK3 = ?
* `(a)` `0`
* `(b)` `1`
* `(c)` `2`
* `(d)` `div3`
* `(e)` `div5`
### Solution
* We create a format string `"FizzBuzz%u"`, and find a way to set the starting index and the string length to get the desired output:
```c
string literal: "fizzbuzz%u"
offset: 0 4 8
```
| Condition | Starting Index | Length |
|:-----------------:|:--------------:|:------:|
| `n % 3 == 0` | 0 | 4 |
| `n % 5 == 0` | 4 | 4 |
| `n % 15 == 0` | 0 | 8 |
| none of the above | 8 | 2 |
* The `length` is already determined by `length = (2 << div3) << div5`, so let's focus on the starting index.
* Note that the starting index is `(MSG_LEN >> KK1) >> (KK2 << KK3)`.
#### KK1
* If the current number is neither a multiple of 3 nor a multiple of 5, the starting index must be `MSG_LEN`. We can deduce that `KK1` must be `0` and `KK2 << KK3` must be `0` too. Therefore, the only possible choices for `KK1` are `div5` and `div3`.
* However, `KK1` can't be `div3`. If `KK1` is `div3`, one of `KK2` or `KK3` must be `div5`. If the current number is a multiple of 5 but not a multiple of 3, then `KK2 << KK3` will be greater than `1`, which will make the starting index become lesser than `4`. Hence, `KK1` must be `div5`.
#### KK2
* We already know that `KK1` is `div5`, therefore, one of `KK2` or `KK3` must be `div3`. If `KK3` is `div3` and `KK2` is a non-zero constant, then the result won't match the desired output (where `n % 3 != 0` and `n % 5 != 0`), because `KK2 << KK3` will be greater than `1`, which results in a wrong starting index. As a result, `KK2` must be `div3`.
#### KK3
* After replacing `KK1` and `KK2` with their values, the starting index becomes `(MSG_LEN >> div5) >> (div3 << KK3)`. Then, we take specific conditions into consideration:
* If `n % 3 == 0` but `n % 5 != 0`, then `MSG_LEN` needs to be right-shifted by `4` to become `0`, therefore, `KK3` must be no less than `2`.
* As a result, `KK3` is `2`.
:::success
**Answers**
* KK1: `div5`
* KK2: `div3`
* KK3: `2`
:::
---
## Problem 4
### Task
* Given two numbers `PAGE_QUEUES` and `offset`, observe the code snippet and choose the possible choices for `CASES`:
* possible values of `PAGE_QUEUES`:
* (1 or 2 or 3 or 4)
* (5 or 6 or 7 or 8) × (2^n^), where $1 \leq n \leq 14$
* code snippet:
```c=
#include <stdint.h>
#define ffs32(x) ((__builtin_ffs(x)) - 1)
size_t blockidx;
size_t divident = PAGE_QUEUES;
blockidx = offset >> ffs32(divident);
divident >>= ffs32(divident);
switch (divident) {
CASES
}
```
From [GCC Built-in Functions](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html):
> Built-in Function: int __builtin_ffs (int x)
> * Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.
#### CASES = ? (multiple answers)
* `(a)` `2`
* `(b)` `3`
* `(c)` `4`
* `(d)` `5`
* `(e)` `6`
* `(f)` `7`
* `(g)` `8`
* `(i)` `9`
* `(j)` `10`
### Solution
* We know that `ffs32` returns the index of the least significant 1-bit of a number, which is the same result as `__builtin_ctz`.
According to [GCC Built-in Functions](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html):
> Built-in Function: int __builtin_ctz (unsigned int x)
> * Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.
* Therefore, `divident >>= ffs32(divident)` eliminates all zeros before the least significant 1-bit of the number, so the new `divident` must be odd (`LSB = 1`).
* We know that `PAGE_QUEUES` is assigned to `divendent` previously, and the possible values of `PAGE_QUEUES` are:
* (1 or 2 or 3 or 4)
* (5 or 6 or 7 or 8) × (2^n^), where $1 \leq n \leq 14$
* As a result, the possible choices must be `3`, `5` and `7`.
:::success
**Answer**
* CASES: `3`, `5` and `7`
:::