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;
}
10 changes: 7 additions & 3 deletions exercises/01_variable&add/main.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#include "../exercise.h"
#include <iostream>

// READ: 运算符 <https://zh.cppreference.com/w/cpp/language/expressions#.E8.BF.90.E7.AE.97.E7.AC.A6>

int main(int argc, char **argv) {
// TODO: 补全变量定义并打印加法运算
// x ?
// 定义并初始化变量 x
int x = 10;// 可以改成任何你喜欢的数字

// 打印加法运算
std::cout << x << " + " << x << " = " << x + x << std::endl;

return 0;
}
}
3 changes: 3 additions & 0 deletions exercises/02_function/main.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "../exercise.h"
#include <iostream>

// READ: 声明 <https://zh.cppreference.com/w/cpp/language/declarations>
// NOTICE: cppreference 中的示例中指出了复杂声明的解读法,建议认真阅读。
// 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 @@ -16,4 +18,5 @@ int main(int argc, char **argv) {

int add(int a, int b) {
// TODO: 补全函数定义,但不要移动代码行
return a + b;// 返回两个参数的和
}
15 changes: 8 additions & 7 deletions exercises/03_argument&parameter/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "../exercise.h"
#include <iostream>

// READ: <https://stackoverflow.com/questions/156767/whats-the-difference-between-an-argument-and-a-parameter>
// THINK: 参数都有哪些传递方式?如何选择传递方式?
Expand All @@ -8,19 +9,19 @@ void func(int);
// TODO: 为下列 ASSERT 填写正确的值
int main(int argc, char **argv) {
auto arg = 99;
ASSERT(arg == ?, "arg should be ?");
std::cout << "befor func call: " << arg << std::endl;
ASSERT(arg == 99, "arg should be 99");
std::cout << "before func call: " << arg << std::endl;
func(arg);
ASSERT(arg == ?, "arg should be ?");
ASSERT(arg == 99, "arg should be 99");
std::cout << "after func call: " << arg << std::endl;
return 0;
}

// TODO: 为下列 ASSERT 填写正确的值
void func(int param) {
ASSERT(param == ?, "param should be ?");
std::cout << "befor add: " << param << std::endl;
ASSERT(param == 99, "param should be 99");
std::cout << "before 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;
}
}
13 changes: 7 additions & 6 deletions exercises/04_static/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "../exercise.h"
#include <iostream>

// READ: `static` 关键字 <https://zh.cppreference.com/w/cpp/language/storage_duration>
// THINK: 这个函数的两个 `static` 各自的作用是什么?
Expand All @@ -10,10 +11,10 @@ static int func(int param) {

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;
}
}
26 changes: 15 additions & 11 deletions exercises/05_constexpr/main.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
#include "../exercise.h"

// 修改后的斐波那契函数:使用迭代(动态规划)
constexpr unsigned long long fibonacci(int i) {
switch (i) {
case 0:
return 0;
case 1:
return 1;
default:
return fibonacci(i - 1) + fibonacci(i - 2);
if (i <= 0) return 0;
if (i == 1) return 1;

unsigned long long prev = 0;// F(0)
unsigned long long curr = 1;// F(1)

for (int n = 2; n <= i; ++n) {
unsigned long long next = prev + curr;
prev = curr;
curr = next;
}

return curr;
}

int main(int argc, char **argv) {
constexpr auto FIB20 = fibonacci(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);
const auto ANS = fibonacci(ANS_N);
std::cout << "fibonacci(" << ANS_N << ") = " << ANS << std::endl;

return 0;
}
}
6 changes: 3 additions & 3 deletions exercises/06_array/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ unsigned long long fibonacci(int i) {
return 1;
default:
// TODO: 补全三目表达式缺失的部分
return <condition> ? <cache> : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2));
return arr[i] ? 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");
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");
ASSERT(fibonacci(80) == 23416728348467685, "fibonacci(80) should be 23416728348467685");
return 0;
}
}
9 changes: 6 additions & 3 deletions exercises/07_loop/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
// READ: 纯函数 <https://zh.wikipedia.org/wiki/%E7%BA%AF%E5%87%BD%E6%95%B0>
static unsigned long long fibonacci(int i) {
// TODO: 为缓存设置正确的初始值
static unsigned long long cache[96], cached;
static unsigned long long cache[96] = {0, 1};
static unsigned long long cached = 1;// 已经缓存的最大索引

// TODO: 设置正确的循环条件
for (; false; ++cached) {
cache[cached] = cache[cached - 1] + cache[cached - 2];
// 如果i比已经缓存的最大索引大,就继续计算并缓存
for (; cached < i; ++cached) {
cache[cached + 1] = cache[cached] + cache[cached - 1];
}
return cache[i];
}
Expand Down
10 changes: 8 additions & 2 deletions exercises/08_pointer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
// 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]

// 检查从 ptr 开始,每隔 stride 个元素的 len 个数是否符合斐波那契递推关系
for (int i = 0; i < len - 2; ++i) {
// arr[i+2] = arr[i] + arr[i+1]
if (ptr[(i + 2) * stride] != ptr[i * stride] + ptr[(i + 1) * stride]) {
return false;
}
}
return true;
}

Expand Down
6 changes: 3 additions & 3 deletions exercises/09_enum&union/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ ColorEnum convert_by_pun(Color c) {

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

return pun.e;
pun.c = c; // 将 Color 值赋给 union 的 c 成员
return pun.e;// 通过 e 成员读取 ColorEnum 值
}

int main(int argc, char **argv) {
Expand All @@ -47,4 +47,4 @@ int main(int argc, char **argv) {
ASSERT(convert_by_pun(Color::Yellow) == COLOR_YELLOW, "Type punning conversion");
ASSERT(convert_by_pun(Color::Blue) == COLOR_BLUE, "Type punning conversion");
return 0;
}
}
46 changes: 29 additions & 17 deletions exercises/10_trivial/main.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
#include "../exercise.h"

// READ: Trivial type <https://learn.microsoft.com/zh-cn/cpp/cpp/trivial-standard-layout-and-pod-types?view=msvc-170>
// READ: 枚举类型 <https://zh.cppreference.com/w/cpp/language/enum>

struct FibonacciCache {
unsigned long long cache[16];
int cached;
// `enum` 是 C 的兼容类型,本质上其对应类型的常量。
// 在 `enum` 中定义标识符等价于定义 constexpr 常量,
// 这些标识符不需要前缀,可以直接引用。
// 因此 `enum` 定义会污染命名空间。
enum ColorEnum : unsigned char {
COLOR_RED = 31,
COLOR_GREEN,
COLOR_YELLOW,
COLOR_BLUE,
};

// TODO: 实现正确的缓存优化斐波那契计算
static unsigned long long fibonacci(FibonacciCache &cache, int i) {
for (; false; ++cached) {
cache[cached] = cache[cached - 1] + cache[cached - 2];
}
return cache.cache[i];
// 有作用域枚举型是 C++ 引入的类型安全枚举。
// 其内部标识符需要带前缀引用,如 `Color::Red`。
// 作用域枚举型可以避免命名空间污染,并提供类型安全保证。
enum class Color : int {
Red = COLOR_RED,
Green,
Yellow,
Blue,
};

ColorEnum convert_by_pun(Color c) {
// 正确的转换方式:使用 static_cast
// 首先将作用域枚举转换为底层类型 int,然后再转换为 ColorEnum
return static_cast<ColorEnum>(static_cast<int>(c));
}

int main(int argc, char **argv) {
// TODO: 初始化缓存结构体,使计算正确
// NOTICE: C/C++ 中,读取未初始化的变量(包括结构体变量)是未定义行为
// READ: 初始化的各种写法 <https://zh.cppreference.com/w/cpp/language/initialization>
FibonacciCache fib;
ASSERT(fibonacci(fib, 10) == 55, "fibonacci(10) should be 55");
std::cout << "fibonacci(10) = " << fibonacci(fib, 10) << std::endl;
ASSERT(convert_by_pun(Color::Red) == COLOR_RED, "Type punning conversion");
ASSERT(convert_by_pun(Color::Green) == COLOR_GREEN, "Type punning conversion");
ASSERT(convert_by_pun(Color::Yellow) == COLOR_YELLOW, "Type punning conversion");
ASSERT(convert_by_pun(Color::Blue) == COLOR_BLUE, "Type punning conversion");
return 0;
}
}
55 changes: 51 additions & 4 deletions exercises/11_method/main.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,69 @@
#include "../exercise.h"
#include <iostream>

struct Fibonacci {
unsigned long long cache[128];
int cached;

// TODO: 实现正确的缓存优化斐波那契计算
unsigned long long get(int i) {
for (; false; ++cached) {
cache[cached] = cache[cached - 1] + cache[cached - 2];
// 如果请求的索引超出了当前缓存的范围,扩展缓存
if (i >= cached) {
// 确保至少有两个基础值来计算
if (cached < 2) {
// 如果缓存为空,初始化前两个值
if (cached == 0) {
cache[0] = 0;// F(0)
cached = 1;
}
if (cached == 1) {
cache[1] = 1;// F(1)
cached = 2;
}
}

// 计算并缓存从当前缓存位置到i的斐波那契数
for (int j = cached; j <= i; ++j) {
cache[j] = cache[j - 1] + cache[j - 2];
++cached;
}
}

// 返回缓存中的值
return cache[i];
}
};

int main(int argc, char **argv) {
// TODO: 初始化缓存结构体,使计算正确
Fibonacci fib;
// 使用聚合初始化:第一个花括号初始化cache数组,第二个值初始化cached
Fibonacci fib = {{0, 1}, 2};// 直接初始化前两个值和cached计数器

// 或者使用值初始化,然后在get函数中动态计算
// Fibonacci fib = {}; // 所有成员初始化为0,get函数会处理初始化

// 验证斐波那契数列
std::cout << "F(0) = " << fib.get(0) << std::endl; // 0
std::cout << "F(1) = " << fib.get(1) << std::endl; // 1
std::cout << "F(2) = " << fib.get(2) << std::endl; // 1
std::cout << "F(3) = " << fib.get(3) << std::endl; // 2
std::cout << "F(4) = " << fib.get(4) << std::endl; // 3
std::cout << "F(5) = " << fib.get(5) << std::endl; // 5
std::cout << "F(6) = " << fib.get(6) << std::endl; // 8
std::cout << "F(7) = " << fib.get(7) << std::endl; // 13
std::cout << "F(8) = " << fib.get(8) << std::endl; // 21
std::cout << "F(9) = " << fib.get(9) << std::endl; // 34
std::cout << "F(10) = " << fib.get(10) << std::endl;// 55

// 测试断言
ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55");
std::cout << "fibonacci(10) = " << fib.get(10) << std::endl;

// 测试缓存效果:多次获取应该从缓存直接返回
std::cout << "\nTesting cache performance:" << std::endl;
std::cout << "F(15) = " << fib.get(15) << std::endl;// 610
std::cout << "F(20) = " << fib.get(20) << std::endl;// 6765
std::cout << "F(10) = " << fib.get(10) << std::endl;// 55 - 应该从缓存直接返回

return 0;
}
}
24 changes: 22 additions & 2 deletions exercises/12_method_const/main.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
#include "../exercise.h"
#include <iostream>

// READ: 有 cv 限定符的成员函数 <https://zh.cppreference.com/w/cpp/language/member_functions>

struct Fibonacci {
int numbers[11];

// TODO: 修改方法签名和实现,使测试通过
int get(int i) {
// 需要添加 const 限定符,因为这个方法会在 const 对象上调用
int get(int i) const {
// 检查索引是否在有效范围内
if (i >= 0 && i < 11) {
return numbers[i];
}
// 如果索引越界,返回 -1 作为错误值
return -1;
}
};

int main(int argc, char **argv) {
// 使用 constexpr 创建常量对象
// 注意:这里需要双花括号进行聚合初始化
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;

// 测试其他值
std::cout << "fibonacci(0) = " << FIB.get(0) << std::endl;
std::cout << "fibonacci(1) = " << FIB.get(1) << std::endl;
std::cout << "fibonacci(2) = " << FIB.get(2) << std::endl;
std::cout << "fibonacci(5) = " << FIB.get(5) << std::endl;

return 0;
}
}
Loading