Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion exercises/00_hello_world/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

int main(int argc, char **argv) {
// TODO: 在控制台输出 "Hello, InfiniTensor!" 并换行
std::cout : "Hello, InfiniTensor!" + std::endl;
std::cout << "Hello, InfiniTensor!" <<std::endl;
return 0;
}
2 changes: 1 addition & 1 deletion exercises/01_variable&add/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

int main(int argc, char **argv) {
// TODO: 补全变量定义并打印加法运算
// x ?
int x =1;
std::cout << x << " + " << x << " = " << x + x << std::endl;
return 0;
}
4 changes: 2 additions & 2 deletions exercises/02_function/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// NOTICE: 补充由内而外读法的机翻解释 <https://learn.microsoft.com/zh-cn/cpp/c-language/interpreting-more-complex-declarators?view=msvc-170>

// TODO: 在这里声明函数

int add(int a, int b);
int main(int argc, char **argv) {
ASSERT(add(123, 456) == 123 + 456, "add(123, 456) should be 123 + 456");

Expand All @@ -15,5 +15,5 @@ int main(int argc, char **argv) {
}

int add(int a, int b) {
// TODO: 补全函数定义,但不要移动代码行
return a+b;
}
19 changes: 7 additions & 12 deletions exercises/03_argument&parameter/main.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
#include "../exercise.h"

// READ: <https://stackoverflow.com/questions/156767/whats-the-difference-between-an-argument-and-a-parameter>
// THINK: 参数都有哪些传递方式?如何选择传递方式?
void func(int&);

void func(int);

// TODO: 为下列 ASSERT 填写正确的值
int main(int argc, char **argv) {
auto arg = 99;
ASSERT(arg == ?, "arg should be ?");
ASSERT(arg == 99, "arg should be 99");
std::cout << "befor func call: " << arg << std::endl;
func(arg);
ASSERT(arg == ?, "arg should be ?");
ASSERT(arg == 100, "arg should be 100");
std::cout << "after func call: " << arg << std::endl;
return 0;
}

// TODO: 为下列 ASSERT 填写正确的值
void func(int param) {
ASSERT(param == ?, "param should be ?");
void func(int& param) {
ASSERT(param == 99, "param should be 99");
std::cout << "befor add: " << param << std::endl;
param += 1;
ASSERT(param == ?, "param should be ?");
ASSERT(param == 100, "param should be 100");
std::cout << "after add: " << param << std::endl;
}
}
16 changes: 6 additions & 10 deletions exercises/04_static/main.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
#include "../exercise.h"

// READ: `static` 关键字 <https://zh.cppreference.com/w/cpp/language/storage_duration>
// THINK: 这个函数的两个 `static` 各自的作用是什么?
static int func(int param) {
static int static_ = param;
// std::cout << "static_ = " << static_ << std::endl;
return static_++;
}

int main(int argc, char **argv) {
// TODO: 将下列 `?` 替换为正确的数字
ASSERT(func(5) == ?, "static variable value incorrect");
ASSERT(func(4) == ?, "static variable value incorrect");
ASSERT(func(3) == ?, "static variable value incorrect");
ASSERT(func(2) == ?, "static variable value incorrect");
ASSERT(func(1) == ?, "static variable value incorrect");
ASSERT(func(5) == 5, "static variable value incorrect");
ASSERT(func(4) == 6, "static variable value incorrect");
ASSERT(func(3) == 7, "static variable value incorrect");
ASSERT(func(2) == 8, "static variable value incorrect");
ASSERT(func(1) == 9, "static variable value incorrect");
return 0;
}
}
28 changes: 22 additions & 6 deletions exercises/05_constexpr/main.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
#include "../exercise.h"
#include <iostream>

constexpr unsigned long long fibonacci(int i) {
// 递归 constexpr 版本(只适合小 n,在编译期演示用)
constexpr unsigned long long fibonacci_constexpr(int i) {
switch (i) {
case 0:
return 0;
case 1:
return 1;
default:
return fibonacci(i - 1) + fibonacci(i - 2);
return fibonacci_constexpr(i - 1) + fibonacci_constexpr(i - 2);
}
}

// 迭代版本,O(n),适合运行时大 n
unsigned long long fibonacci_iter(int n) {
if (n == 0) return 0;
if (n == 1) return 1;

unsigned long long a = 0, b = 1, c = 0;
for (int i = 2; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return b;
}

int main(int argc, char **argv) {
constexpr auto FIB20 = fibonacci(20);
// 编译期计算小规模
constexpr auto FIB20 = fibonacci_constexpr(20);
ASSERT(FIB20 == 6765, "fibonacci(20) should be 6765");
std::cout << "fibonacci(20) = " << FIB20 << std::endl;

// TODO: 观察错误信息,修改一处,使代码编译运行
// PS: 编译运行,但是不一定能算出结果……
// 大规模用迭代计算(运行时)
constexpr auto ANS_N = 90;
constexpr auto ANS = fibonacci(ANS_N);
auto ANS = fibonacci_iter(ANS_N);
std::cout << "fibonacci(" << ANS_N << ") = " << ANS << std::endl;

return 0;
Expand Down
8 changes: 4 additions & 4 deletions exercises/06_array/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ unsigned long long fibonacci(int i) {
case 1:
return 1;
default:
// TODO: 补全三目表达式缺失的部分
return <condition> ? <cache> : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2));
// 补全三目表达式:如果已计算则返回缓存值,否则计算并存储
return arr[i] != 0 ? arr[i] : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2));
}
}

int main(int argc, char **argv) {
// TODO: 为此 ASSERT 填写正确的值
ASSERT(sizeof(arr) == ?, "sizeof array is size of all its elements");
// 数组大小断言:90个unsigned long long元素,每个8字节,总大小720
ASSERT(sizeof(arr) == 720, "sizeof array is size of all its elements");
// ---- 不要修改以下代码 ----
ASSERT(fibonacci(2) == 1, "fibonacci(2) should be 1");
ASSERT(fibonacci(20) == 6765, "fibonacci(20) should be 6765");
Expand Down
21 changes: 13 additions & 8 deletions exercises/07_loop/main.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
#include "../exercise.h"

// TODO: 改正函数实现,实现正确的缓存优化斐波那契计算
// THINk: 这个函数是一个纯函数(pure function)吗?
// READ: 纯函数 <https://zh.wikipedia.org/wiki/%E7%BA%AF%E5%87%BD%E6%95%B0>
// 改正函数实现,实现正确的缓存优化斐波那契计算
// 这个函数不是纯函数,因为它使用了static变量(缓存),其结果依赖于内部状态
static unsigned long long fibonacci(int i) {
// TODO: 为缓存设置正确的初始值
static unsigned long long cache[96], cached;
// TODO: 设置正确的循环条件
for (; false; ++cached) {
cache[cached] = cache[cached - 1] + cache[cached - 2];
// 为缓存设置正确的初始值,fib[0]=0, fib[1]=1
static unsigned long long cache[96] = {0, 1};
static bool initialized = false;

// 只初始化一次,预计算所有需要的斐波那契值
if (!initialized) {
for (int j = 2; j < 96; ++j) {
cache[j] = cache[j - 1] + cache[j - 2];
}
initialized = true;
}

return cache[i];
}

Expand Down
16 changes: 13 additions & 3 deletions exercises/08_pointer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@
// READ: 数组向指针退化 <https://zh.cppreference.com/w/cpp/language/array#%E6%95%B0%E7%BB%84%E5%88%B0%E6%8C%87%E9%92%88%E7%9A%84%E9%80%80%E5%8C%96>
bool is_fibonacci(int *ptr, int len, int stride) {
ASSERT(len >= 3, "`len` should be at least 3");
// TODO: 编写代码判断从 ptr 开始,每 stride 个元素取 1 个元素,组成长度为 n 的数列是否满足
// arr[i + 2] = arr[i] + arr[i + 1]
// 遍历需要验证的每一组三项(从第3个元素开始,对应索引2)
for (int i = 2; i < len; ++i) {
// 计算当前组的三个元素:i-2项、i-1项、i项(按stride步长偏移)
int a = *(ptr + (i - 2) * stride); // 第i-2个元素
int b = *(ptr + (i - 1) * stride); // 第i-1个元素
int c = *(ptr + i * stride); // 第i个元素
// 验证斐波那契规则:c是否等于a+b,不满足则直接返回false
if (c != a + b) {
return false;
}
}
// 所有组均满足规则,返回true
return true;
}

Expand All @@ -25,4 +35,4 @@ int main(int argc, char **argv) {
ASSERT(!is_fibonacci(arr2 + 1, 10 , 2), "guard check" );
// clang-format on
return 0;
}
}
6 changes: 3 additions & 3 deletions exercises/09_enum&union/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ ColorEnum convert_by_pun(Color c) {
};

TypePun pun;
// TODO: 补全类型双关转换

return pun.e;
// 补全类型双关转换:将输入的Color值存入union,然后通过另一种类型取出
pun.c = c; // 存储Color类型的值到union
return pun.e; // 从union中取出ColorEnum类型的值
}

int main(int argc, char **argv) {
Expand Down
23 changes: 15 additions & 8 deletions exercises/10_trivial/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@ struct FibonacciCache {
int cached;
};

// TODO: 实现正确的缓存优化斐波那契计算
// 实现正确的缓存优化斐波那契计算
static unsigned long long fibonacci(FibonacciCache &cache, int i) {
for (; false; ++cached) {
cache[cached] = cache[cached - 1] + cache[cached - 2];
// 循环条件:若已缓存的长度 < i,继续预计算到第i项(确保cache[i]存在)
// 从当前已缓存的下一项开始计算(cached初始为2,从索引2开始)
for (; cache.cached <= i; ++cache.cached) {
// 斐波那契规则:第n项 = 第n-1项 + 第n-2项
cache.cache[cache.cached] = cache.cache[cache.cached - 1] + cache.cache[cache.cached - 2];
}
return cache.cache[i];
}

int main(int argc, char **argv) {
// TODO: 初始化缓存结构体,使计算正确
// NOTICE: C/C++ 中,读取未初始化的变量(包括结构体变量)是未定义行为
// READ: 初始化的各种写法 <https://zh.cppreference.com/w/cpp/language/initialization>
FibonacciCache fib;
// 初始化缓存结构体:
// 1. cache[0] = 0, cache[1] = 1(斐波那契起始值),其余元素默认0
// 2. cached = 2(标记已预计算到索引1,下一个待计算索引为2)
FibonacciCache fib = {
.cache = {0, 1}, // 聚合初始化:显式初始化前2项,剩余项默认0
.cached = 2 // 已缓存的项数(索引0和1已初始化,故为2)
};

ASSERT(fibonacci(fib, 10) == 55, "fibonacci(10) should be 55");
std::cout << "fibonacci(10) = " << fibonacci(fib, 10) << std::endl;
return 0;
}
}
19 changes: 14 additions & 5 deletions exercises/11_method/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,28 @@ struct Fibonacci {
unsigned long long cache[128];
int cached;

// TODO: 实现正确的缓存优化斐波那契计算
// 实现缓存优化的斐波那契计算:按需预计算,避免重复计算
unsigned long long get(int i) {
for (; false; ++cached) {
// 循环条件:若已缓存项数 < 目标索引i,继续计算到第i项
// 从当前已缓存的下一项(cached)开始,直到覆盖目标i
for (; cached <= i; ++cached) {
// 斐波那契核心规则:第n项 = 第n-1项 + 第n-2项
cache[cached] = cache[cached - 1] + cache[cached - 2];
}
// 此时cache[i]已预计算完成,直接返回
return cache[i];
}
};

int main(int argc, char **argv) {
// TODO: 初始化缓存结构体,使计算正确
Fibonacci fib;
// 初始化结构体:显式设置斐波那契起始值和已缓存项数
// 避免读取未初始化变量(未定义行为)
Fibonacci fib = {
.cache = {0, 1}, // 聚合初始化:cache[0]=0(第0项)、cache[1]=1(第1项),剩余元素默认0
.cached = 2 // 已缓存项数:索引0和1已初始化,下一个待计算索引为2
};

ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55");
std::cout << "fibonacci(10) = " << fib.get(10) << std::endl;
return 0;
}
}
9 changes: 6 additions & 3 deletions exercises/12_method_const/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@

struct Fibonacci {
int numbers[11];
// TODO: 修改方法签名和实现,使测试通过
int get(int i) {
// 修改方法签名:添加const修饰成员函数,允许constexpr/const对象调用
// 实现逻辑:返回数组中索引i对应的元素
int get(int i) const {
return numbers[i];
}
};

int main(int argc, char **argv) {
// constexpr对象初始化:数组已包含斐波那契数列前11项(索引0~10)
Fibonacci constexpr FIB{{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}};
ASSERT(FIB.get(10) == 55, "fibonacci(10) should be 55");
std::cout << "fibonacci(10) = " << FIB.get(10) << std::endl;
return 0;
}
}
22 changes: 7 additions & 15 deletions exercises/13_class/main.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
#include "../exercise.h"

// C++ 中,`class` 和 `struct` 之间的**唯一区别**是
// `class` 默认访问控制符是 `private`,
// `struct` 默认访问控制符是 `public`。
// READ: 访问说明符 <https://zh.cppreference.com/w/cpp/language/access>

// 这个 class 中的字段被 private 修饰,只能在 class 内部访问。
// 因此必须提供构造器来初始化字段。
// READ: 构造器 <https://zh.cppreference.com/w/cpp/language/constructor>
class Fibonacci {
size_t cache[16];
int cached;

public:
// TODO: 实现构造器
// Fibonacci()
Fibonacci() {
cache[0] = 0;
cache[1] = 1;
cached = 2;
}

// TODO: 实现正确的缓存优化斐波那契计算
size_t get(int i) {
for (; false; ++cached) {
for (; cached <= i; ++cached) {
cache[cached] = cache[cached - 1] + cache[cached - 2];
}
return cache[i];
}
};

int main(int argc, char **argv) {
// 现在类型拥有无参构造器,声明时会直接调用。
// 这个写法不再是未定义行为了。
Fibonacci fib;
ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55");
std::cout << "fibonacci(10) = " << fib.get(10) << std::endl;
return 0;
}
}
Loading