# 正課第四次作業
###### tags: `NTOU CSE C++ Programming`
> 教學文件和作業說明文件: https://hackmd.io/@kogiokka/ntou-cse-cpp-nav
承[第十次實習作業](https://hackmd.io/@kogiokka/ntou-cse-cpp-practice-10),擴充 `BigInt` 類別。
練習下列 C++ 語法:
* this pointer
* static members
* new and delete
* operator overloading
## 規定
* 繳交日期: 6月10日(以教師伺服器上顯示的日期為準)
* 電子檔繳交方式:將程式碼和心得壓縮成 **ZIP** 檔上傳到教師的伺服器。檔案格式為`<學號>-<姓名>.zip`,例如:`11057666-陳小明.zip`。
* 紙本繳交方式:上課交紙本(A4紙)的程式碼和心得
## 需求
1. 記憶體指令用 `new` 和 `delete`。
1. 更改動態陣列 `m_digits` 型別。定義一個 `char` 陣列存放 `BigInt` 的位數,每個`char` 存1位數。`char` 底層為介於-128至127的整數,足夠存一位整數0至9。
1. 容量大小(`m_capacity`)預設為 10。
## 擴充 `BigInt` (1)
###### 80分
完成下列要求:
* 建立 constructors 和 destructors。
* 利用**靜態成員**(static member)記錄當前的`BigInt` 物件個數,並定義一個函式 `BigInt::GetCount()` 回傳該數值。
* 運算子多載:
* `+`、`-` 、`++` 、`--` 、`<<` 和 `=`(60分)
* `+=`、`-=`、`*` 和 `*=`(20分)
> Hint 1:可以用暴力解法(連加)。例如: $100 \times 3$ => 連續加 3 次 100 => 300
> Hint 2:用人的計算方法,每個位數相乘後先記錄下來,再全部加起來。
> 位數相乘的結果在新陣列中存放的索引值會是兩個位數的索引值的和,即
> $\text{result}[i + j] = \text{num1}[i] * \text{num2}[j]$
## 擴充 `BigInt`(2)
###### 20分
完成下列與除法相關的運算子:
* `operator/`
* `operator/=`
除法結果應為整數:
* $\frac{100}{3} = 33$
* $\frac{10}{3} = 3$
> Hint 1:用暴力解法(連減)。
> 例如:
> $100 \div 3 \Rightarrow 100 = 33 \times 3 \Rightarrow 33$
> $10 \div 4 \Rightarrow 10 = 2 \times 4 \Rightarrow 2$
> $10 \div -4 \Rightarrow 10 = -2 \times -4 \Rightarrow -2$
> $-10 \div 4 \Rightarrow -10 = -2 \times 4 \Rightarrow -2$
> $-10 \div -4 \Rightarrow -10 = 2 \times -4 \Rightarrow 2$
> Hint 2:用人計算的方法。一樣是被除數連續減掉除數,只是從高位數開始連減,往低位數走。
> 例如:
> $$39427 \div 44 \\ \Rightarrow 39427 = 4400 \times 8 + 4227 \\ \Rightarrow 4227 = 440 \times 9 + 267 \\ \Rightarrow 267 = 44 \times 6 + 3 \\
> $$
## BigComplexNumber
###### 40分
擴充 BigInt 完成下列與複數(complex number)相關的函式:
* 定義成員函式 `BigComplexNumber::SetValue(int real, int imaginary)`,接受兩個 `int` 參數設定複數值。
* 運算子多載:
* `+`、`-`、`*` 和 `<<`(20分)
* `=`、`+=`、`-=` 和 `*=`(20分)
複數的運算:
* 加法: $(a + bi) + (c + di) = (a + c) + (b + d)i$
* 減法: $(a + bi) - (c + di) = (a - c) + (b - d)i$
* 乘法: $(a + bi) * (c + di) = (ac - bd) + (bc + ad)i$
## 範例程式
* [正課第四次作業範例程式:BigInt_PRO(Google Drive)](https://drive.google.com/drive/folders/14PryccYDqL1lOTtPqfCkTOYufLIOOfZ9?usp=sharing)
* `BigInt_PRO` 是接續第十次實習作業的 `BigInt_operators` 程式碼。
* 使用 CMake 搭配 Visual Studio 的話可執行檔和測試檔會自動放在 `out/install/` 資料夾之下,不用額外做設定。其他環境下可能要設定安裝路徑的變數: `CMAKE_INSTALL_PREFIX`。
* 專案的資料夾路徑不能有中文字元,否則用 Visual Studio 編譯 CMake 專案會出錯。
### BigInt_PRO
#### 編譯和執行
> 不是使用 Visual Studio 嗎?請見 [CMake專案建置](https://hackmd.io/@kogiokka/ntou-cse-cpp-tutorial-02)。
在 Visual Studio 選擇**開啟本機資料夾**或**檔案 → 開啟 → 資料夾**,並選擇`BigInt_PRO/`的資料夾。Visual Studio 會自動開始設定 CMake 專案,可能會花一點時間。
等待輸出欄位的訊息跑完之後,在上方工具列的**選取啟動項目**選 `bigint_pro.exe` 就可以自動編譯執行了。
#### 專案目錄結構
```txt
BigInt_PRO
├── answer.txt
├── BigComplexNumber.cpp
├── BigComplexNumber.hpp
├── BigInt.cpp
├── BigInt.hpp
├── CMakeLists.txt
└── main.cpp
```
#### 原始碼
`CMakeLists.txt`
```cmake=
cmake_minimum_required(VERSION 3.12)
project("Big Integer PRO")
add_executable(bigint_pro)
target_sources(bigint_pro
PRIVATE
"main.cpp"
"BigInt.cpp"
"BigComplexNumber.cpp"
)
```
`main.cpp`
```cpp=
#include "BigComplexNumber.hpp"
#include "BigInt.hpp"
#include <iostream>
#include <string>
using std::cerr;
using std::cout;
using std::endl;
// void testBigIntPro();
// void testBigComplexNumber();
int main()
{
cout << R"(
_____________ ________ _____ _______________________
___ __ )__(_)______ ____ _/________ /_ ___ __ \__ __ \_ __ \
__ __ |_ /__ __ `/__ / __ __ \ __/ __ /_/ /_ /_/ / / / /
_ /_/ /_ / _ /_/ /__/ / _ / / / /_ _ ____/_ _, _// /_/ /
/_____/ /_/ _\__, / /___/ /_/ /_/\__/ /_/ /_/ |_| \____/
/____/
)";
cout << "CMake project setup successfully!" << endl;
cout << "Uncomment the test cases to proceed.\n" << endl;
// testBigIntPro();
// testBigComplexNumber();
return 0;
}
// Test cases
/**
void testBigIntPro()
{
BigInt x, y("1234"), z("00000987654321");
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
BigInt i(44, 2);
BigInt j(i);
BigInt k(10);
cout << "i j k values: " << i << ' ' << j << ' ' << k << endl;
cout << "Total BigInt Object Count: " << BigInt::GetCount() << endl;
x = y = "987654321098765432109876543210987654321098765432109876543210";
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
y = 10;
y *= -88;
cout << "y values: " << y << endl;
y = 10;
y *= i;
cout << "y values: " << y << endl;
y = x / 8;
cout << "y values: " << y << endl;
x /= -8;
cout << "x values: " << x << endl;
x /= i;
cout << "x values: " << x << endl;
y = 10;
y += -88;
cout << "y values: " << y << endl;
y = 10;
y += i;
cout << "y values: " << y << endl;
y = 10;
y -= -88;
cout << "y values: " << y << endl;
y = 10;
y -= i;
cout << "y values: " << y << endl;
x = i + 3 + j * 2 * k;
cout << "x values: " << x << endl;
x = i - 3 - j * 2 * k;
cout << "x values: " << x << endl;
cout << "k values: " << k++ << ' ' << k << endl;
k = 10;
x = ++k++;
cout << "x k values: " << x << ' ' << k << endl;
k = 10;
x = --k--;
cout << "x k values: " << x << ' ' << k << endl;
x = y = "987654321098765432109876543210";
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
}
void testBigComplexNumber()
{
BigComplexNumber x, y("10", "20"), z(2, 4);
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
x = y + z;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
x += y;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
y += z;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
y.SetValue(10, 20);
z.SetValue(4, 2);
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
x = y - z;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
x -= y;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
z -= y;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
y.SetValue(2, 4);
z.SetValue(10, 20);
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
x = y * z;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
x *= y;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
z *= y;
cout << "x y z values: " << x << ' ' << y << ' ' << z << endl;
}
*/
```
`BigInt.hpp`
```cpp=
#ifndef BIGINT_H
#define BIGINT_H
#include <ostream>
/**
* @class BigInt
*
* Arbitrary-precision integers.
*/
class BigInt
{
friend std::ostream& operator<<(std::ostream&, const BigInt&);
public:
/**
Default constructor
Create a BigInt with default value 0 and default capacity 10.
*/
BigInt();
/**
Destructor
Destroy the instance and release the memory.
*/
~BigInt();
/**
Constructor
Create a BigInt from an integer.
*/
explicit BigInt(const int value, const int size = 10);
/**
Constructor
Create a BigInt from a string.
*/
explicit BigInt(const char* const value, const int size = 10);
/**
Copy Constructor
Create a BigInt from another BigInt.
*/
BigInt(const BigInt& value);
/**
Addition operation. Add another BigInt.
*/
void Add(const BigInt& value);
/**
Addition operation. Add an integer of type int.
*/
void Add(const int value);
/**
Addition operation. Add a value from a string.
*/
void Add(const char* const value);
/**
Reset the integer to zero.
*/
void SetZero();
/**
Get the number of BigInt instances.
*/
static int GetCount();
/**
Arithmetic Operators
BigInt operator+(const BigInt& other) const;
BigInt operator+(int value) const;
BigInt operator-(const BigInt& other) const;
BigInt operator-(int value) const;
BigInt operator*(const BigInt& multiplier) const;
BigInt operator*(int multiplier) const;
BigInt operator/(const BigInt& divisor) const;
BigInt operator/(int divisor) const;
*/
/**
Assignment Operators
BigInt& operator=(const BigInt& other);
BigInt& operator=(int value);
BigInt& operator=(const char* const value);
BigInt& operator-=(const BigInt& other);
BigInt& operator-=(int value);
BigInt& operator+=(const BigInt& other);
BigInt& operator+=(int value);
BigInt& operator*=(const BigInt& multiplier);
BigInt& operator*=(int multiplier);
BigInt& operator/=(const BigInt& divisor);
BigInt& operator/=(int divisor);
*/
/**
Increment/Decrement Operators
BigInt& operator++();
BigInt operator++(int);
BigInt& operator--();
BigInt operator--(int);
*/
/**
Optional: Comparison Operators
bool operator<(const BigInt& other) const;
bool operator>(const BigInt& other) const;
bool operator==(const BigInt& other) const;
bool operator>=(const BigInt& other) const;
bool operator<=(const BigInt& other) const;
*/
/**
Optional: Unary Minus Operator
BigInt operator-() const;
*/
private:
/// An dynamic array storing the digits.
char* m_digits;
/// Size of the dynamic array.
int m_capacity;
/// Number of digits in the integer
int m_numDigits;
/// sign of the integer
int m_sign;
/// Count of instances
static int COUNT;
};
```
`BigInt.cpp`
```cpp=
#include "BigInt.hpp"
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
using std::cout;
using std::endl;
using std::ostream;
using std::ostringstream;
BigInt::BigInt()
{
m_capacity = 10;
m_digits = new char[m_capacity];
SetZero();
// TODO
}
BigInt::~BigInt()
{
assert(m_digits != nullptr);
delete[] m_digits;
// TODO
}
BigInt::BigInt(const char* const value, const int size)
: m_digits(nullptr)
, m_capacity(size)
, m_numDigits(0)
{
// TODO
}
BigInt::BigInt(const int value, const int size)
: m_digits(nullptr)
, m_capacity(size)
, m_numDigits(0)
{
// TODO
}
BigInt::BigInt(const BigInt& other)
: m_digits(nullptr)
, m_capacity(other.m_capacity)
, m_numDigits(other.m_numDigits)
, m_sign(other.m_sign)
{
// TODO
}
void BigInt::SetZero()
{
for (int i = 0; i < m_capacity; i++) {
m_digits[i] = 0;
}
m_numDigits = 0;
}
void BigInt::Add(const int value)
{
// TODO
}
void BigInt::Add(const char* const value)
{
// TODO
}
void BigInt::Add(const BigInt& value)
{
// TODO
}
/******************************************************************************/
/**
* 擴充 BigInt(1)
*
* 一、完成下列運算子多載:(60分)
*
* 1. operator+
* 2. operator-
* 3. operator++
* 4. operator--
* 5. operator<<
* 6. operator=
*
* 二、完成下列運算子多載:(20分)
*
* 1. operator+=
* 2. operator-=
* 3. operator*
* 4. operator*=
*
*/
/******************************************************************************/
/**
* 擴充 BigInt(2)
*
* 完成下列運算子多載:(20分)
*
* 1. operator/
* 2. operator/=
*
*/
/******************************************************************************/
```
`BigComplexNumber.hpp`
```cpp=
#ifndef BIGCOMPLEXNUMBER_H
#define BIGCOMPLEXNUMBER_H
#include <ostream>
#include "BigInt.hpp"
/**
* @class BigComplexNumber
*
* Arbitrary-precision integers with complex number support.
*/
class BigComplexNumber
{
friend std::ostream& operator<<(std::ostream&, const BigComplexNumber&);
public:
/**
Default constructor
Create a BigComplexNumber with default value 0+0i and default capacity 10.
*/
BigComplexNumber();
/**
Destructor
Destroy the instance and release the memory.
*/
~BigComplexNumber();
/**
Constructor
Create a BigComplexNumber from an integer of real part and an integer of imaginary part.
*/
BigComplexNumber(int real, int imaginary);
/**
Constructor
Create a BigComplexNumber from a string of real part and a string of imaginary part.
*/
BigComplexNumber(const char* real, const char* imaginary);
/**
Copy Constructor
Create a BigComplexNumber from another BigComplexNumber.
*/
BigComplexNumber(const BigComplexNumber& value);
/**
Set the value with a real part integer and an imaginary part integer.
*/
void SetValue(int real, int imaginary);
/**
Arithmetic Operators
BigComplexNumber operator+(const BigComplexNumber& other) const;
BigComplexNumber operator-(const BigComplexNumber& other) const;
BigComplexNumber operator*(const BigComplexNumber& other) const;
*/
/**
Assignment Operators
BigComplexNumber& operator=(const BigComplexNumber& other);
BigComplexNumber& operator+=(const BigComplexNumber& other);
BigComplexNumber& operator-=(const BigComplexNumber& other);
BigComplexNumber& operator*=(const BigComplexNumber& other);
*/
private:
/// A BigInt representing the real part.
BigInt m_re;
/// A BigInt representing the imaginary part.
BigInt m_im;
};
#endif // BIGCOMPLEXNUMBER_H
```
`BigComplexNumber.cpp`
```cpp=
#include "BigComplexNumber.hpp"
#include <iostream>
using std::ostream;
BigComplexNumber::BigComplexNumber()
: m_re()
, m_im()
{
}
BigComplexNumber::~BigComplexNumber()
{
// TODO
}
BigComplexNumber::BigComplexNumber(const BigComplexNumber& other)
{
// TODO
}
BigComplexNumber::BigComplexNumber(int real, int imaginary)
{
// TODO
}
BigComplexNumber::BigComplexNumber(const char* real, const char* imaginary)
{
// TODO
}
void BigComplexNumber::SetValue(int real, int imaginary)
{
// TODO
}
/******************************************************************************/
/**
* Arithmetic operators
*
* 1. operator+
* 2. operator-
* 3. operator*
* 4. operator<<
*/
/******************************************************************************/
/**
* Assignment operators
*
* 1. operator=
* 2. operator+=
* 3. operator-=
* 4. operator*=
*/
```