目的: 檢驗學員對 bitops、浮點數運算,及數值系統的認知
1
考慮以下定點數運算:
#include <stdint.h>
typedef int32_t fix16_t;
#define FIX16_ONE 0x00010000 /* 1.0 in fixed-point representation */
輔助函式:
static inline float fix16_to_float(fix16_t a)
{
return (float) a / FIX16_ONE;
}
static inline fix16_t float_to_fix16(float a)
{
/* Round to nearest fixed-point value */
return (fix16_t)(a * FIX16_ONE + (a >= 0 ? 0.5f : -0.5f));
}
static inline fix16_t int_to_fix16(int a)
{
return a * FIX16_ONE;
}
藉此打造 tanh 函數,用法如下:
printf("%f\n", fix16_to_float(fix16_tanh(float_to_fix16(0.5))));
參考執行結果是 0.462097
以下是實作程式碼: (部分遮蔽)
static inline fix16_t fix16_mul(fix16_t x, fix16_t y)
{
int64_t res = (int64_t) x * y;
return (fix16_t) (res >> 16);
}
static inline fix16_t fix16_div(fix16_t a, fix16_t b)
{
if (b == 0) /* Avoid division by zero */
return 0;
fix16_t result = (((int64_t) a) << 16) / ((int64_t) b);
return result;
}
fix16_t fix16_exp(fix16_t in)
{
if (in == 0)
return FIX16_ONE;
if (in == FIX16_ONE)
return AAAA /* precomputed exp(1) in fixed-point */;
if (in >= 681391)
return BBBB;
if (in <= -772243)
return 0;
int neg = (in < 0);
if (neg)
in = -in;
fix16_t result = in + FIX16_ONE;
fix16_t term = in;
for (uint_fast8_t i = 2; i < 30; i++) {
term = fix16_mul(term, fix16_div(in, int_to_fix16(i)));
result += term;
/* Break early if the term is sufficiently small */
if ((term < 500) && ((i > 15) || (term < 20)))
break;
}
if (neg)
result = CCCC;
return result;
}
/* tanh(x) is defined as (exp(x) - exp(-x)) / (exp(x) + exp(-x)). */
fix16_t fix16_tanh(fix16_t in)
{
fix16_t e_x = fix16_exp(in);
fix16_t m_e_x = fix16_exp(-in);
return fix16_div(e_x - m_e_x, e_x + m_e_x);
}
補完程式碼,使其運作符合預期。書寫規範:
0x
開頭,英文字母大寫FIX16_ONE
及 fix16_
開頭的函式呼叫,不含空白字元2
承測驗 1
,以下程式碼實作倍精度的 tanh(x)
,不使用任何 FPU 指令,程式碼可見 tanh.c (部分遮蔽)
書寫規範:
0x
開頭,英文字母小寫0x
開頭,英文字母小寫參考資料:
3
我們嘗試改寫 Linux 核心的紅黑樹,藉此開發 C++ std::map 的替代品,測試程式碼如下:
/* Custom entry structure embedding a map node. */
typedef struct {
map_node_t node; /* Must be the first member if using container_of on node. */
char *key; /* Key used for ordering. */
int value; /* Associated value. */
} my_entry_t;
/* Extracts the key from the given node. */
static void *my_get_key(map_node_t *node)
{
return (void *)(((my_entry_t *)node)->key);
}
int main(void)
{
/* Initialize the map with our key extraction function and default comparator. */
map_t map;
map_init(&map, my_get_key, NULL);
/* Allocate and initialize several entries. */
my_entry_t *entry1 = malloc(sizeof(my_entry_t));
entry1->key = "apple";
entry1->value = 10;
my_entry_t *entry2 = malloc(sizeof(my_entry_t));
entry2->key = "banana";
entry2->value = 20;
my_entry_t *entry3 = malloc(sizeof(my_entry_t));
entry3->key = "cherry";
entry3->value = 30;
/* Insert the entries into the map. */
if (map_push(&map, entry1->key, &entry1->node) != 0)
printf("Duplicate key: %s\n", entry1->key);
if (map_push(&map, entry2->key, &entry2->node) != 0)
printf("Duplicate key: %s\n", entry2->key);
if (map_push(&map, entry3->key, &entry3->node) != 0)
printf("Duplicate key: %s\n", entry3->key);
/* Search for an entry by key ("banana") and then erase it. */
map_node_t *node = map_find(&map, "banana");
if (node) {
my_entry_t *found_entry = container_of(node, my_entry_t, node);
printf("Found entry: Key = %s, Value = %d\n", found_entry->key, found_entry->value);
/* Erase the found entry from the map. */
map_erase(&map, node);
/* After erasing, free the memory for the entry. */
free(found_entry);
} else {
printf("Key 'banana' not found.\n");
}
/* Traverse and print all remaining entries in the map in sorted order. */
printf("All entries in the map after erasing 'banana':\n");
map_foreach(node, &map) {
my_entry_t *entry = container_of(node, my_entry_t, node);
printf("Key: %s, Value: %d\n", entry->key, entry->value);
}
free(entry1);
free(entry3);
return 0;
}
預期執行輸出:
Found entry: Key = banana, Value = 20
All entries in the map after erasing 'banana':
Key: apple, Value: 10
Key: cherry, Value: 30
C++ std::map 用紅黑樹實作,std::unordered_map 用雜湊表實作。
程式碼可見 map.c (部分遮蔽),補完程式碼以符合預期。作答規範:
rotate
,注意要用一致的程式碼縮排風格,注意空白RB_