diff --git a/exercises/00_hello_world/main.cpp b/exercises/00_hello_world/main.cpp index 8866f3c15..fa454e132 100644 --- a/exercises/00_hello_world/main.cpp +++ b/exercises/00_hello_world/main.cpp @@ -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; } diff --git a/exercises/01_variable&add/main.cpp b/exercises/01_variable&add/main.cpp index 5014863fd..54e042181 100644 --- a/exercises/01_variable&add/main.cpp +++ b/exercises/01_variable&add/main.cpp @@ -5,6 +5,7 @@ int main(int argc, char **argv) { // TODO: 补全变量定义并打印加法运算 // x ? + int x=10; std::cout << x << " + " << x << " = " << x + x << std::endl; return 0; } diff --git a/exercises/02_function/main.cpp b/exercises/02_function/main.cpp index b5eef7f28..aaff5ad41 100644 --- a/exercises/02_function/main.cpp +++ b/exercises/02_function/main.cpp @@ -5,6 +5,7 @@ // NOTICE: 补充由内而外读法的机翻解释 // 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"); @@ -16,4 +17,5 @@ int main(int argc, char **argv) { int add(int a, int b) { // TODO: 补全函数定义,但不要移动代码行 + return a+b; } diff --git a/exercises/03_argument¶meter/main.cpp b/exercises/03_argument¶meter/main.cpp index 7fb5d3c2f..0ff2e2d54 100644 --- a/exercises/03_argument¶meter/main.cpp +++ b/exercises/03_argument¶meter/main.cpp @@ -8,19 +8,19 @@ 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 == 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 ?"); + 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; } diff --git a/exercises/04_static/main.cpp b/exercises/04_static/main.cpp index f107762fa..64f417694 100644 --- a/exercises/04_static/main.cpp +++ b/exercises/04_static/main.cpp @@ -10,10 +10,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; } diff --git a/exercises/05_constexpr/main.cpp b/exercises/05_constexpr/main.cpp index d1db6c9d8..bebb3c494 100644 --- a/exercises/05_constexpr/main.cpp +++ b/exercises/05_constexpr/main.cpp @@ -18,8 +18,9 @@ int main(int argc, char **argv) { // TODO: 观察错误信息,修改一处,使代码编译运行 // PS: 编译运行,但是不一定能算出结果…… - constexpr auto ANS_N = 90; - constexpr auto ANS = fibonacci(ANS_N); + constexpr auto ANS_N = 10; + //constexpr auto ANS = fibonacci(ANS_N); + auto ANS = fibonacci(ANS_N); std::cout << "fibonacci(" << ANS_N << ") = " << ANS << std::endl; return 0; diff --git a/exercises/06_array/main.cpp b/exercises/06_array/main.cpp index 61ed99ec0..5089ea10f 100644 --- a/exercises/06_array/main.cpp +++ b/exercises/06_array/main.cpp @@ -11,13 +11,15 @@ unsigned long long fibonacci(int i) { return 1; default: // TODO: 补全三目表达式缺失的部分 - return ? : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2)); + //return ? : (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) == ?, "sizeof array is size of all its elements"); + ASSERT(sizeof(arr) == sizeof(unsigned long long) * 90, "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"); diff --git a/exercises/07_loop/main.cpp b/exercises/07_loop/main.cpp index 44fd835cd..b7df5482a 100644 --- a/exercises/07_loop/main.cpp +++ b/exercises/07_loop/main.cpp @@ -5,9 +5,17 @@ // READ: 纯函数 static unsigned long long fibonacci(int i) { // TODO: 为缓存设置正确的初始值 - static unsigned long long cache[96], cached; + static unsigned long long cache[96] = {0, 1}; // 缓存数组,第 0 项为 0,第 1 项为 1 + static int cached = 2; // 即将计算但尚未计算的索引 // TODO: 设置正确的循环条件 - for (; false; ++cached) { + + // 如果缓存中已经有计算过的结果 + if (i < cached) { + return cache[i]; + } + + // 如果缓存不足,计算 Fibonacci 数 + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/08_pointer/main.cpp b/exercises/08_pointer/main.cpp index ba37173f5..100dfc177 100644 --- a/exercises/08_pointer/main.cpp +++ b/exercises/08_pointer/main.cpp @@ -5,6 +5,15 @@ 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] + for (int i = 0; i < len - 2; ++i) { + int a = *(ptr + i * stride); + int b = *(ptr + (i + 1) * stride); + int c = *(ptr + (i + 2) * stride); + + if (c != a + b) { + return false; + } + } return true; } diff --git a/exercises/09_enum&union/main.cpp b/exercises/09_enum&union/main.cpp index 3f2cec768..5779dd314 100644 --- a/exercises/09_enum&union/main.cpp +++ b/exercises/09_enum&union/main.cpp @@ -37,6 +37,7 @@ ColorEnum convert_by_pun(Color c) { TypePun pun; // TODO: 补全类型双关转换 + pun.c = c; return pun.e; } diff --git a/exercises/10_trivial/main.cpp b/exercises/10_trivial/main.cpp index 6ba23e48e..2aa76aa26 100644 --- a/exercises/10_trivial/main.cpp +++ b/exercises/10_trivial/main.cpp @@ -4,22 +4,55 @@ struct FibonacciCache { unsigned long long cache[16]; - int cached; + int cached; // 最早的尚未被计算器的位置索引 }; +/* // 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]; } +*/ +// TODO: 实现正确的缓存优化斐波那契计算 +static unsigned long long fibonacci(FibonacciCache &cache, int i) { + // 如果请求的斐波那契数已经在缓存中,直接返回 + if (i < cache.cached) { + return cache.cache[i]; + } + + if (cache.cached < 2) { + cache.cache[0] = 0; + cache.cache[1] = 1; + cache.cached = 2; + } + + // 否则,计算并缓存从 cache.cached 到 i 的斐波那契数 + for (int j = cache.cached; j <= i; ++j) { + if (j == 0) { + cache.cache[j] = 0; + } else if (j == 1) { + cache.cache[j] = 1; + } else { + cache.cache[j] = cache.cache[j - 1] + cache.cache[j - 2]; + } + } + + // 更新缓存中已经计算过的斐波那契数的个数 + cache.cached = i + 1; + + // 返回请求的斐波那契数 + return cache.cache[i]; +} int main(int argc, char **argv) { // TODO: 初始化缓存结构体,使计算正确 // NOTICE: C/C++ 中,读取未初始化的变量(包括结构体变量)是未定义行为 // READ: 初始化的各种写法 - FibonacciCache fib; + FibonacciCache fib{}; ASSERT(fibonacci(fib, 10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fibonacci(fib, 10) << std::endl; return 0; diff --git a/exercises/11_method/main.cpp b/exercises/11_method/main.cpp index 0e08e0a36..ef1ba7bcf 100644 --- a/exercises/11_method/main.cpp +++ b/exercises/11_method/main.cpp @@ -4,12 +4,44 @@ struct Fibonacci { unsigned long long cache[128]; int cached; + // 构造函数:初始化缓存 + Fibonacci() { + // 假设 cache[0] = 0, cache[1] = 1 + cache[0] = 0; + cache[1] = 1; + cached = 2; // 目前缓存了前两个数 + } + // TODO: 实现正确的缓存优化斐波那契计算 unsigned long long get(int i) { + + /* for (; false; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; + */ + + if (i < cached) { + return cache[i]; + } + + // 否则,计算并缓存从 cached 到 i 的斐波那契数 + for (int j = cached; j <= i; ++j) { + if (j == 0) { + cache[j] = 0; + } else if (j == 1) { + cache[j] = 1; + } else { + cache[j] = cache[j - 1] + cache[j - 2]; + } + } + + // 更新缓存中已经计算过的斐波那契数的个数 + cached = i + 1; + + // 返回请求的斐波那契数 + return cache[i]; } }; diff --git a/exercises/12_method_const/main.cpp b/exercises/12_method_const/main.cpp index 5521be4da..ebbea40ed 100644 --- a/exercises/12_method_const/main.cpp +++ b/exercises/12_method_const/main.cpp @@ -5,7 +5,8 @@ struct Fibonacci { int numbers[11]; // TODO: 修改方法签名和实现,使测试通过 - int get(int i) { + constexpr int get(int i) const { + return numbers[i]; } }; diff --git a/exercises/13_class/main.cpp b/exercises/13_class/main.cpp index 9afa98c5b..76c69c8fb 100644 --- a/exercises/13_class/main.cpp +++ b/exercises/13_class/main.cpp @@ -15,10 +15,17 @@ class Fibonacci { public: // TODO: 实现构造器 // Fibonacci() + Fibonacci() { + cache[0] = 0; + cache[1] = 1; + cached = 2; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + if(icache); + } // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + ~DynFibonacci() { + delete[] cache; + } // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + for (; cached<=i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; diff --git a/exercises/16_class_move/main.cpp b/exercises/16_class_move/main.cpp index 8d2c421da..2ce634ccf 100644 --- a/exercises/16_class_move/main.cpp +++ b/exercises/16_class_move/main.cpp @@ -14,34 +14,50 @@ class DynFibonacci { int cached; public: - // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + // 动态设置容量的构造器 + DynFibonacci(int capacity) : cache(new size_t[capacity]), cached(1) { + cache[0] = 0; + cache[1] = 1; + } - // TODO: 实现移动构造器 - DynFibonacci(DynFibonacci &&) noexcept = delete; + // 移动构造器 + DynFibonacci(DynFibonacci&& other) noexcept + : cache(other.cache), cached(other.cached) { + other.cache = nullptr; + other.cached = 0; + } - // TODO: 实现移动赋值 - // NOTICE: ⚠ 注意移动到自身问题 ⚠ - DynFibonacci &operator=(DynFibonacci &&) noexcept = delete; + // 移动赋值运算符 + DynFibonacci& operator=(DynFibonacci&& other) noexcept { + if (this != &other) { + delete[] cache; + cache = other.cache; + cached = other.cached; + other.cache = nullptr; + other.cached = 0; + } + return *this; + } - // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + // 析构器 + ~DynFibonacci() { + delete[] cache; + } - // TODO: 实现正确的缓存优化斐波那契计算 + // 缓存优化的斐波那契计算 size_t operator[](int i) { - for (; false; ++cached) { + while (cached < i) { + ++cached; cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; } - // NOTICE: 不要修改这个方法 size_t operator[](int i) const { ASSERT(i <= cached, "i out of range"); return cache[i]; } - // NOTICE: 不要修改这个方法 bool is_alive() const { return cache; } diff --git a/exercises/16_class_move/main_Zero_Progress_Yet.cpp b/exercises/16_class_move/main_Zero_Progress_Yet.cpp new file mode 100644 index 000000000..8d2c421da --- /dev/null +++ b/exercises/16_class_move/main_Zero_Progress_Yet.cpp @@ -0,0 +1,66 @@ +#include "../exercise.h" + +// READ: 左值右值(概念) +// READ: 左值右值(细节) +// READ: 关于移动语义 +// READ: 如果实现移动构造 + +// READ: 移动构造函数 +// READ: 移动赋值 +// READ: 运算符重载 + +class DynFibonacci { + size_t *cache; + int cached; + +public: + // TODO: 实现动态设置容量的构造器 + DynFibonacci(int capacity): cache(new ?), cached(?) {} + + // TODO: 实现移动构造器 + DynFibonacci(DynFibonacci &&) noexcept = delete; + + // TODO: 实现移动赋值 + // NOTICE: ⚠ 注意移动到自身问题 ⚠ + DynFibonacci &operator=(DynFibonacci &&) noexcept = delete; + + // TODO: 实现析构器,释放缓存空间 + ~DynFibonacci(); + + // TODO: 实现正确的缓存优化斐波那契计算 + size_t operator[](int i) { + for (; false; ++cached) { + cache[cached] = cache[cached - 1] + cache[cached - 2]; + } + return cache[i]; + } + + // NOTICE: 不要修改这个方法 + size_t operator[](int i) const { + ASSERT(i <= cached, "i out of range"); + return cache[i]; + } + + // NOTICE: 不要修改这个方法 + bool is_alive() const { + return cache; + } +}; + +int main(int argc, char **argv) { + DynFibonacci fib(12); + ASSERT(fib[10] == 55, "fibonacci(10) should be 55"); + + DynFibonacci const fib_ = std::move(fib); + ASSERT(!fib.is_alive(), "Object moved"); + ASSERT(fib_[10] == 55, "fibonacci(10) should be 55"); + + DynFibonacci fib0(6); + DynFibonacci fib1(12); + + fib0 = std::move(fib1); + fib0 = std::move(fib0); + ASSERT(fib0[10] == 55, "fibonacci(10) should be 55"); + + return 0; +} diff --git a/exercises/17_class_derive/main.cpp b/exercises/17_class_derive/main.cpp index 819ae72fc..790084fc0 100644 --- a/exercises/17_class_derive/main.cpp +++ b/exercises/17_class_derive/main.cpp @@ -50,9 +50,13 @@ int main(int argc, char **argv) { B b = B(3); // TODO: 补全三个类型的大小 - static_assert(sizeof(X) == ?, "There is an int in X"); - static_assert(sizeof(A) == ?, "There is an int in A"); - static_assert(sizeof(B) == ?, "B is an A with an X"); + //static_assert(sizeof(X) == ?, "There is an int in X"); + //static_assert(sizeof(A) == ?, "There is an int in A"); + //static_assert(sizeof(B) == ?, "B is an A with an X"); + + static_assert(sizeof(X) == 4, "There is an int in X"); + static_assert(sizeof(A) == 4, "There is an int in A"); + static_assert(sizeof(B) == 8, "B is an A with an X"); i = 0; std::cout << std::endl diff --git a/exercises/18_class_virtual/main.cpp b/exercises/18_class_virtual/main.cpp index ac6382413..173c526f2 100644 --- a/exercises/18_class_virtual/main.cpp +++ b/exercises/18_class_virtual/main.cpp @@ -42,6 +42,8 @@ int main(int argc, char **argv) { C c; D d; + /* + ASSERT(a.virtual_name() == '?', MSG); ASSERT(b.virtual_name() == '?', MSG); ASSERT(c.virtual_name() == '?', MSG); @@ -51,10 +53,23 @@ int main(int argc, char **argv) { ASSERT(c.direct_name() == '?', MSG); ASSERT(d.direct_name() == '?', MSG); + */ + + ASSERT(a.virtual_name() == 'A', MSG); + ASSERT(b.virtual_name() == 'B', MSG); + ASSERT(c.virtual_name() == 'C', MSG); + ASSERT(d.virtual_name() == 'C', MSG); + ASSERT(a.direct_name() == 'A', MSG); + ASSERT(b.direct_name() == 'B', MSG); + ASSERT(c.direct_name() == 'C', MSG); + ASSERT(d.direct_name() == 'D', MSG); + A &rab = b; B &rbc = c; C &rcd = d; + /* + ASSERT(rab.virtual_name() == '?', MSG); ASSERT(rbc.virtual_name() == '?', MSG); ASSERT(rcd.virtual_name() == '?', MSG); @@ -62,19 +77,44 @@ int main(int argc, char **argv) { ASSERT(rbc.direct_name() == '?', MSG); ASSERT(rcd.direct_name() == '?', MSG); + */ + + ASSERT(rab.virtual_name() == 'B', MSG); + ASSERT(rbc.virtual_name() == 'C', MSG); + ASSERT(rcd.virtual_name() == 'C', MSG); + ASSERT(rab.direct_name() == 'A', MSG); + ASSERT(rbc.direct_name() == 'B', MSG); + ASSERT(rcd.direct_name() == 'C', MSG); + A &rac = c; B &rbd = d; + /* + ASSERT(rac.virtual_name() == '?', MSG); ASSERT(rbd.virtual_name() == '?', MSG); ASSERT(rac.direct_name() == '?', MSG); ASSERT(rbd.direct_name() == '?', MSG); + */ + + ASSERT(rac.virtual_name() == 'C', MSG); + ASSERT(rbd.virtual_name() == 'C', MSG); + ASSERT(rac.direct_name() == 'A', MSG); + ASSERT(rbd.direct_name() == 'B', MSG); + A &rad = d; + /* + ASSERT(rad.virtual_name() == '?', MSG); ASSERT(rad.direct_name() == '?', MSG); + */ + + ASSERT(rad.virtual_name() == 'C', MSG); + ASSERT(rad.direct_name() == 'A', MSG); + return 0; } diff --git a/exercises/19_class_virtual_destruct/main.cpp b/exercises/19_class_virtual_destruct/main.cpp index cdd54f74f..9d79662d8 100644 --- a/exercises/19_class_virtual_destruct/main.cpp +++ b/exercises/19_class_virtual_destruct/main.cpp @@ -5,61 +5,84 @@ struct A { // TODO: 正确初始化静态字段 - static int num_a = 0; + //static int num_a = 0; + static int num_a; // 类内声明 A() { ++num_a; + std::cout<<"construct A"<name() == '?', "Fill in the correct value for a->name()"); - ASSERT(b->name() == '?', "Fill in the correct value for b->name()"); + ASSERT(A::num_a == 2, "Fill in the correct value for A::num_a"); + ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b"); + ASSERT(a->name() == 'A', "Fill in the correct value for a->name()"); + ASSERT(b->name() == 'B', "Fill in the correct value for b->name()"); + + std::cout<<"------------------"<name() == '?', "Fill in the correct value for ab->name()"); + ASSERT(A::num_a == 1, "Fill in the correct value for A::num_a"); + ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b"); + ASSERT(ab->name() == 'B', "Fill in the correct value for ab->name()"); + + std::cout<<"------------------"<name()"); + //B &bb = *ab; + B &bb = dynamic_cast(*ab); + ASSERT(bb.name() == 'B', "Fill in the correct value for bb->name()"); + + std::cout<<"------------------"< // TODO: 将这个函数模板化 -int plus(int a, int b) { +template +T plus(T a, T b) { return a + b; } @@ -14,7 +15,8 @@ int main(int argc, char **argv) { ASSERT(plus(1.25f, 2.5f) == 3.75f, "Plus two float"); ASSERT(plus(1.25, 2.5) == 3.75, "Plus two double"); // TODO: 修改判断条件使测试通过 - ASSERT(plus(0.1, 0.2) == 0.3, "How to make this pass?"); + //ASSERT(plus(0.1, 0.2) == 0.3, "How to make this pass?"); + ASSERT(std::abs(plus(0.1, 0.2) - 0.3) < 1e-15, "How to make this pass?"); return 0; } diff --git a/exercises/21_runtime_datatype/main.cpp b/exercises/21_runtime_datatype/main.cpp index 9c4bf376a..a4a86c345 100644 --- a/exercises/21_runtime_datatype/main.cpp +++ b/exercises/21_runtime_datatype/main.cpp @@ -18,15 +18,34 @@ struct TaggedUnion { }; // TODO: 将这个函数模板化用于 sigmoid_dyn +/* float sigmoid(float x) { return 1 / (1 + std::exp(-x)); } +*/ +template +T sigmoid(T x) { + return 1 / (1 + std::exp(-x)); +} +/* TaggedUnion sigmoid_dyn(TaggedUnion x) { TaggedUnion ans{x.type}; // TODO: 根据 type 调用 sigmoid return ans; } +*/ +TaggedUnion sigmoid_dyn(TaggedUnion x) { + TaggedUnion ans; + ans.type = x.type; // 设置返回值的类型 + if (x.type == DataType::Float) { + ans.f = sigmoid(x.f); // 调用float版本的sigmoid + } else { + ans.d = sigmoid(x.d); // 调用double版本的sigmoid + } + return ans; +} + // ---- 不要修改以下代码 ---- int main(int argc, char **argv) { diff --git a/exercises/22_class_template/main.cpp b/exercises/22_class_template/main.cpp index 2a702ecc0..03069c70e 100644 --- a/exercises/22_class_template/main.cpp +++ b/exercises/22_class_template/main.cpp @@ -1,7 +1,9 @@ #include "../exercise.h" +#include // READ: 类模板 +/* template struct Tensor4D { unsigned int shape[4]; @@ -31,6 +33,72 @@ struct Tensor4D { return *this; } }; +*/ + +template +struct Tensor4D { + unsigned int shape[4]; + T *data; + + Tensor4D(unsigned int const shape_[4], T const *data_) { + // TODO: 填入正确的 shape 并计算 size + for (int i = 0; i < 4; ++i) { + shape[i] = shape_[i]; + } + unsigned int size = shape[0] * shape[1] * shape[2] * shape[3]; + data = new T[size]; + std::memcpy(data, data_, size * sizeof(T)); + } + ~Tensor4D() { + delete[] data; + } + + // 为了保持简单,禁止复制和移动 + Tensor4D(Tensor4D const &) = delete; + Tensor4D(Tensor4D &&) noexcept = delete; + + // 这个加法需要支持“单向广播”。 + // 具体来说,`others` 可以具有与 `this` 不同的形状,形状不同的维度长度必须为 1。 + // `others` 长度为 1 但 `this` 长度不为 1 的维度将发生广播计算。 + // 例如,`this` 形状为 `[1, 2, 3, 4]`,`others` 形状为 `[1, 2, 1, 4]`, + // 则 `this` 与 `others` 相加时,3 个形状为 `[1, 2, 1, 4]` 的子张量各自与 `others` 对应项相加。 + Tensor4D &operator+=(Tensor4D const &others) { + const unsigned int s1 = others.shape[1]; + const unsigned int s2 = others.shape[2]; + const unsigned int s3 = others.shape[3]; + const unsigned int stride1 = s1 * s2 * s3; + const unsigned int stride2 = s2 * s3; + const unsigned int stride3 = s3; + + for (unsigned int i0 = 0; i0 < shape[0]; ++i0) { + for (unsigned int i1 = 0; i1 < shape[1]; ++i1) { + for (unsigned int i2 = 0; i2 < shape[2]; ++i2) { + for (unsigned int i3 = 0; i3 < shape[3]; ++i3) { + unsigned int this_idx = i0 * (shape[1] * shape[2] * shape[3]) + + i1 * (shape[2] * shape[3]) + + i2 * shape[3] + + i3; + + unsigned int j0 = (others.shape[0] == 1) ? 0 : i0; + unsigned int j1 = (others.shape[1] == 1) ? 0 : i1; + unsigned int j2 = (others.shape[2] == 1) ? 0 : i2; + unsigned int j3 = (others.shape[3] == 1) ? 0 : i3; + + unsigned int others_idx = j0 * stride1 + + j1 * stride2 + + j2 * stride3 + + j3; + + data[this_idx] += others.data[others_idx]; + } + } + } + } + return *this; + } +}; + + // ---- 不要修改以下代码 ---- int main(int argc, char **argv) { diff --git a/exercises/23_template_const/main.cpp b/exercises/23_template_const/main.cpp index e0105e168..ec5161130 100644 --- a/exercises/23_template_const/main.cpp +++ b/exercises/23_template_const/main.cpp @@ -3,6 +3,7 @@ // READ: 模板非类型实参 +/* template struct Tensor { unsigned int shape[N]; @@ -39,32 +40,82 @@ struct Tensor { return index; } }; +*/ + + +template +struct Tensor { + unsigned int shape[N]; + T *data; + + Tensor(unsigned int const shape_[N]) { + unsigned int size = 1; + for (unsigned int i = 0; i < N; ++i) { + shape[i] = shape_[i]; + size *= shape[i]; + } + data = new T[size]; + std::memset(data, 0, size * sizeof(T)); + } + ~Tensor() { + delete[] data; + } + + // 为了保持简单,禁止复制和移动 + Tensor(Tensor const &) = delete; + Tensor(Tensor &&) noexcept = delete; + + T &operator[](unsigned int const indices[N]) { + return data[data_index(indices)]; + } + T const &operator[](unsigned int const indices[N]) const { + return data[data_index(indices)]; + } + +private: + unsigned int data_index(unsigned int const indices[N]) const { + unsigned int index = 0; + for (unsigned int i = 0; i < N; ++i) { + ASSERT(indices[i] < shape[i], "Invalid index"); + unsigned int product = 1; + for (unsigned int j = i + 1; j < N; ++j) { + product *= shape[j]; + } + index += indices[i] * product; + } + return index; + } +}; // ---- 不要修改以下代码 ---- int main(int argc, char **argv) { { - unsigned int shape[]{2, 3, 4, 5}; - auto tensor = Tensor<4, int>(shape); + unsigned int shape[]{2, 3, 4, 5}; // 张量形状为 [2,3,4,5],总元素数 = 2*3*4*5 = 120 + auto tensor = Tensor<4, int>(shape); // 创建四维张量 + // 测试点 1:索引 [0,0,0,0] (索引从0开始) unsigned int i0[]{0, 0, 0, 0}; tensor[i0] = 1; ASSERT(tensor[i0] == 1, "tensor[i0] should be 1"); ASSERT(tensor.data[0] == 1, "tensor[i0] should be 1"); + // 测试点 2:索引 [1,2,3,4] (索引从0开始) unsigned int i1[]{1, 2, 3, 4}; - tensor[i1] = 2; + tensor[i1] = 2; // 写入最后一个元素(线性索引 119) ASSERT(tensor[i1] == 2, "tensor[i1] should be 2"); ASSERT(tensor.data[119] == 2, "tensor[i1] should be 2"); } { - unsigned int shape[]{7, 8, 128}; - auto tensor = Tensor<3, float>(shape); + unsigned int shape[]{7, 8, 128}; // 张量形状为 [7,8,128],总元素数 = 7*8*128 = 7168 + auto tensor = Tensor<3, float>(shape); // 创建三维张量 - unsigned int i0[]{0, 0, 0}; + // 测试点 1:索引 [0,0,0] + unsigned int i0[]{0, 0, 0}; tensor[i0] = 1.f; ASSERT(tensor[i0] == 1.f, "tensor[i0] should be 1"); ASSERT(tensor.data[0] == 1.f, "tensor[i0] should be 1"); + // 测试点 2:索引 [3,4,99] unsigned int i1[]{3, 4, 99}; tensor[i1] = 2.f; ASSERT(tensor[i1] == 2.f, "tensor[i1] should be 2"); diff --git a/exercises/24_std_array/main.cpp b/exercises/24_std_array/main.cpp index c29718d9d..7ae3b7d69 100644 --- a/exercises/24_std_array/main.cpp +++ b/exercises/24_std_array/main.cpp @@ -5,24 +5,25 @@ // READ: std::array // TODO: 将下列 `?` 替换为正确的代码 -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ { std::array arr{{1, 2, 3, 4, 5}}; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); + ASSERT(arr.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(arr) == 20, "Fill in the correct value."); int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(arr.?, ans, ?) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(arr.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { std::array arr; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); + ASSERT(arr.size() == 8, "Fill in the correct value."); + ASSERT(sizeof(arr) == 64, "Fill in the correct value."); } { std::array arr{"Hello, InfiniTensor!"}; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); - ASSERT(std::strcmp(arr.?, "Hello, InfiniTensor!") == 0, "Fill in the correct value."); + ASSERT(arr.size() == 21, "Fill in the correct value."); + ASSERT(sizeof(arr) == 21, "Fill in the correct value."); + ASSERT(std::strcmp(arr.data(), "Hello, InfiniTensor!") == 0, "Fill in the correct value."); } return 0; } diff --git a/exercises/25_std_vector/main.cpp b/exercises/25_std_vector/main.cpp index f9e41bb78..0095442be 100644 --- a/exercises/25_std_vector/main.cpp +++ b/exercises/25_std_vector/main.cpp @@ -8,81 +8,82 @@ int main(int argc, char **argv) { { std::vector vec{1, 2, 3, 4, 5}; - ASSERT(vec.size() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); // THINK: `std::vector` 的大小是什么意思?与什么有关? - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(vec.?, ans, sizeof(ans)) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(vec.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { std::vector vec{1, 2, 3, 4, 5}; { - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); double ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(vec.?, ans, sizeof(ans)) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(vec.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { vec.push_back(6); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 6, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); vec.pop_back(); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); } { vec[4] = 6; - ASSERT(vec[0] == ?, "Fill in the correct value."); - ASSERT(vec[1] == ?, "Fill in the correct value."); - ASSERT(vec[2] == ?, "Fill in the correct value."); - ASSERT(vec[3] == ?, "Fill in the correct value."); - ASSERT(vec[4] == ?, "Fill in the correct value."); + ASSERT(vec[0] == 1, "Fill in the correct value."); + ASSERT(vec[1] == 2, "Fill in the correct value."); + ASSERT(vec[2] == 3, "Fill in the correct value."); + ASSERT(vec[3] == 4, "Fill in the correct value."); + ASSERT(vec[4] == 6, "Fill in the correct value."); } { // THINK: `std::vector` 插入删除的时间复杂度是什么? - vec.insert(?, 1.5); + // 这里要改成+v.begin() + vec.insert(vec.begin() + 1, 1.5); ASSERT((vec == std::vector{1, 1.5, 2, 3, 4, 6}), "Make this assertion pass."); - vec.erase(?); + vec.erase(vec.begin() + 3); ASSERT((vec == std::vector{1, 1.5, 2, 4, 6}), "Make this assertion pass."); } { vec.shrink_to_fit(); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.capacity() == 5, "Fill in the correct value."); vec.clear(); ASSERT(vec.empty(), "`vec` is empty now."); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 0, "Fill in the correct value."); + ASSERT(vec.capacity() == 5, "Fill in the correct value."); } } { - std::vector vec(?, ?); // TODO: 调用正确的构造函数 + std::vector vec(48, 'z'); // TODO: 调用正确的构造函数 ASSERT(vec[0] == 'z', "Make this assertion pass."); ASSERT(vec[47] == 'z', "Make this assertion pass."); ASSERT(vec.size() == 48, "Make this assertion pass."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); { auto capacity = vec.capacity(); vec.resize(16); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in a correct identifier."); + ASSERT(vec.size() == 16, "Fill in the correct value."); + ASSERT(vec.capacity() == capacity, "Fill in a correct identifier."); } { vec.reserve(256); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 16, "Fill in the correct value."); + ASSERT(vec.capacity() == 256, "Fill in the correct value."); } { vec.push_back('a'); vec.push_back('b'); vec.push_back('c'); vec.push_back('d'); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); - ASSERT(vec[15] == ?, "Fill in the correct value."); - ASSERT(vec[?] == 'a', "Fill in the correct value."); - ASSERT(vec[?] == 'b', "Fill in the correct value."); - ASSERT(vec[?] == 'c', "Fill in the correct value."); - ASSERT(vec[?] == 'd', "Fill in the correct value."); + ASSERT(vec.size() == 20, "Fill in the correct value."); + ASSERT(vec.capacity() == 256, "Fill in the correct value."); + ASSERT(vec[15] == 'z', "Fill in the correct value."); + ASSERT(vec[16] == 'a', "Fill in the correct value."); + ASSERT(vec[17] == 'b', "Fill in the correct value."); + ASSERT(vec[18] == 'c', "Fill in the correct value."); + ASSERT(vec[19] == 'd', "Fill in the correct value."); } } diff --git a/exercises/26_std_vector_bool/main.cpp b/exercises/26_std_vector_bool/main.cpp index b4ab4f9c4..c9ba17f74 100644 --- a/exercises/26_std_vector_bool/main.cpp +++ b/exercises/26_std_vector_bool/main.cpp @@ -6,29 +6,30 @@ // TODO: 将下列 `?` 替换为正确的代码 int main(int argc, char **argv) { - std::vector vec(?, ?);// TODO: 正确调用构造函数 + std::vector vec(100, true);// TODO: 正确调用构造函数 ASSERT(vec[0], "Make this assertion pass."); ASSERT(vec[99], "Make this assertion pass."); ASSERT(vec.size() == 100, "Make this assertion pass."); // NOTICE: 平台相关!注意 CI:Ubuntu 上的值。 std::cout << "sizeof(std::vector) = " << sizeof(std::vector) << std::endl; - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + // ????? 这个答案似乎与编译器相关 + ASSERT(sizeof(vec) == 40, "Fill in the correct value."); { vec[20] = false; - ASSERT(?vec[20], "Fill in `vec[20]` or `!vec[20]`."); + ASSERT(!vec[20], "Fill in `vec[20]` or `!vec[20]`."); } { vec.push_back(false); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(?vec[100], "Fill in `vec[100]` or `!vec[100]`."); + ASSERT(vec.size() == 101, "Fill in the correct value."); + ASSERT(!vec[100], "Fill in `vec[100]` or `!vec[100]`."); } { auto ref = vec[30]; - ASSERT(?ref, "Fill in `ref` or `!ref`"); + ASSERT(ref, "Fill in `ref` or `!ref`"); ref = false; - ASSERT(?ref, "Fill in `ref` or `!ref`"); + ASSERT(!ref, "Fill in `ref` or `!ref`"); // THINK: WHAT and WHY? - ASSERT(?vec[30], "Fill in `vec[30]` or `!vec[30]`."); + ASSERT(!vec[30], "Fill in `vec[30]` or `!vec[30]`."); } return 0; } diff --git a/exercises/27_strides/main.cpp b/exercises/27_strides/main.cpp index baceaf2a9..98a8a112f 100644 --- a/exercises/27_strides/main.cpp +++ b/exercises/27_strides/main.cpp @@ -13,6 +13,7 @@ using udim = unsigned int; /// @brief 计算连续存储张量的步长 /// @param shape 张量的形状 /// @return 张量每维度的访问步长 +/* std::vector strides(std::vector const &shape) { std::vector strides(shape.size()); // TODO: 完成函数体,根据张量形状计算张量连续存储时的步长。 @@ -20,6 +21,19 @@ std::vector strides(std::vector const &shape) { // 使用逆向迭代器可能可以简化代码 return strides; } +*/ + +std::vector strides(std::vector const &shape) { + std::vector result(shape.size()); + udim cumulative = 1; + auto s_it = shape.rbegin(); + auto r_it = result.rbegin(); + for (; s_it != shape.rend(); ++s_it, ++r_it) { + *r_it = cumulative; + cumulative *= *s_it; + } + return result; +} // ---- 不要修改以下代码 ---- int main(int argc, char **argv) { diff --git a/exercises/28_std_string/main.cpp b/exercises/28_std_string/main.cpp index d8b276274..5fcfdf31d 100644 --- a/exercises/28_std_string/main.cpp +++ b/exercises/28_std_string/main.cpp @@ -10,9 +10,9 @@ int main(int argc, char **argv) { auto world = "world"; // READ: `decltype` 表达式 // READ: `std::is_same_v` 元编程判别 - ASSERT((std::is_same_v), "Fill in the missing type."); - ASSERT((std::is_same_v), "Fill in the missing type."); + ASSERT((std::is_same_v), "Fill in the missing type."); + ASSERT((std::is_same_v), "Fill in the missing type."); // TODO: 将 `?` 替换为正确的字符串 - ASSERT(hello + ", " + world + '!' == "?", "Fill in the missing string."); + ASSERT(hello + ", " + world + '!' == "Hello, world!", "Fill in the missing string."); return 0; } diff --git a/exercises/29_std_map/main.cpp b/exercises/29_std_map/main.cpp index fcccca347..47d024f47 100644 --- a/exercises/29_std_map/main.cpp +++ b/exercises/29_std_map/main.cpp @@ -7,11 +7,13 @@ template bool key_exists(std::map const &map, k const &key) { // TODO: 实现函数 + return map.count(key); } template void set(std::map &map, k key, v value) { // TODO: 实现函数 + map[key]=value; } // ---- 不要修改以下代码 ---- diff --git a/exercises/30_std_unique_ptr/main.cpp b/exercises/30_std_unique_ptr/main.cpp index 9b98b5794..820ac4809 100644 --- a/exercises/30_std_unique_ptr/main.cpp +++ b/exercises/30_std_unique_ptr/main.cpp @@ -53,8 +53,12 @@ int main(int argc, char **argv) { {"fd"}, // TODO: 分析 problems[1] 中资源的生命周期,将记录填入 `std::vector` // NOTICE: 此题结果依赖对象析构逻辑,平台相关,提交时以 CI 实际运行平台为准 - {"", "", "", "", "", "", "", ""}, - {"", "", "", "", "", "", "", ""}, + //{"", "", "", "", "", "", "", ""}, + //{"", "", "", "", "", "", "", ""}, + // 问题1的答案 + {"d", "ffr"}, + // 问题2的答案 + {"d", "d", "r"}, }; // ---- 不要修改以下代码 ---- diff --git a/exercises/31_std_shared_ptr/main.cpp b/exercises/31_std_shared_ptr/main.cpp index febbbcc6f..10da33780 100644 --- a/exercises/31_std_shared_ptr/main.cpp +++ b/exercises/31_std_shared_ptr/main.cpp @@ -5,6 +5,8 @@ // READ: `std::weak_ptr` // TODO: 将下列 `?` 替换为正确的值 + +/* int main(int argc, char **argv) { auto shared = std::make_shared(10); std::shared_ptr ptrs[]{shared, shared, shared}; @@ -43,3 +45,44 @@ int main(int argc, char **argv) { return 0; } +*/ + +// TODO: 将下列 `?` 替换为正确的值 +int main(int argc, char **argv) { + auto shared = std::make_shared(10); + std::shared_ptr ptrs[]{shared, shared, shared}; + + std::weak_ptr observer = shared; + ASSERT(observer.use_count() == 4, ""); + + ptrs[0].reset(); + ASSERT(observer.use_count() == 3, ""); + + ptrs[1] = nullptr; + ASSERT(observer.use_count() == 2, ""); + + ptrs[2] = std::make_shared(*shared); + ASSERT(observer.use_count() == 1, ""); + + ptrs[0] = shared; + ptrs[1] = shared; + ptrs[2] = std::move(shared); + ASSERT(observer.use_count() == 3, ""); + + std::ignore = std::move(ptrs[0]); + ptrs[1] = std::move(ptrs[1]); + ptrs[1] = std::move(ptrs[2]); + ASSERT(observer.use_count() == 2, ""); + + shared = observer.lock(); + ASSERT(observer.use_count() == 3, ""); + + shared = nullptr; + for (auto &ptr : ptrs) ptr = nullptr; + ASSERT(observer.use_count() == 0, ""); + + shared = observer.lock(); + ASSERT(observer.use_count() == 0, ""); + + return 0; +} diff --git a/exercises/32_std_transform/main.cpp b/exercises/32_std_transform/main.cpp index f4dc25a5c..713101345 100644 --- a/exercises/32_std_transform/main.cpp +++ b/exercises/32_std_transform/main.cpp @@ -9,7 +9,10 @@ int main(int argc, char **argv) { std::vector val{8, 13, 21, 34, 55}; // TODO: 调用 `std::transform`,将 `v` 中的每个元素乘以 2,并转换为字符串,存入 `ans` - // std::vector ans + std::vector ans; + // 调用std::transform,使用back_inserter自动填充ans + std::transform(val.begin(), val.end(), std::back_inserter(ans), + [](int x) { return std::to_string(x * 2); }); ASSERT(ans.size() == val.size(), "ans size should be equal to val size"); ASSERT(ans[0] == "16", "ans[0] should be 16"); ASSERT(ans[1] == "26", "ans[1] should be 26"); diff --git a/exercises/33_std_accumulate/main.cpp b/exercises/33_std_accumulate/main.cpp index 6326929d5..bc1e7cab4 100644 --- a/exercises/33_std_accumulate/main.cpp +++ b/exercises/33_std_accumulate/main.cpp @@ -12,6 +12,12 @@ int main(int argc, char **argv) { // - 连续存储; // 的张量占用的字节数 // int size = + int element_count = std::accumulate( + std::begin(shape), std::end(shape), + 1, + std::multiplies() + ); + int size = element_count * sizeof(DataType); // 总字节数 ASSERT(size == 602112, "4x1x3x224x224 = 602112"); return 0; }