From 7e1ad9514340ee01d0cb753fbd5bfd7707c5f208 Mon Sep 17 00:00:00 2001 From: nihonium Date: Thu, 15 Sep 2022 08:21:25 +0300 Subject: [PATCH 1/3] working 1number, not yet splitted --- .../homework/code/0circle/circle.cpp | 3 +- .../code/1number/{number.cpp => main.cpp} | 156 ++++++++++++++++-- 2 files changed, 140 insertions(+), 19 deletions(-) rename seminar02_encapsulation/homework/code/1number/{number.cpp => main.cpp} (70%) diff --git a/seminar02_encapsulation/homework/code/0circle/circle.cpp b/seminar02_encapsulation/homework/code/0circle/circle.cpp index 4d123fe..89b4e78 100644 --- a/seminar02_encapsulation/homework/code/0circle/circle.cpp +++ b/seminar02_encapsulation/homework/code/0circle/circle.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "circle.h" #include "point.h" @@ -25,7 +26,7 @@ void Circle::setRadius(float radius) { mRadius = radius > 0 ? radius : 0; } float Circle::getArea() const { - return mRadius * mRadius * M_PI; + return abs(mRadius * mRadius * M_PI); } float Circle::getDistance(const Point& p) { return mCenter.distance(p) - mRadius; diff --git a/seminar02_encapsulation/homework/code/1number/number.cpp b/seminar02_encapsulation/homework/code/1number/main.cpp similarity index 70% rename from seminar02_encapsulation/homework/code/1number/number.cpp rename to seminar02_encapsulation/homework/code/1number/main.cpp index 55cfbcd..d4a4158 100644 --- a/seminar02_encapsulation/homework/code/1number/number.cpp +++ b/seminar02_encapsulation/homework/code/1number/main.cpp @@ -118,27 +118,45 @@ public: return *this; } - Number operator+(const Number& a) { + Number operator+(Number a) { +#ifdef _DEBUG_ADD + std::cout << "arg1=" << a << "capacity=" << a.capacity << ",size="<< a.size<< std::endl; + std::cout << "arg2=" << *this << "capacity=" << this->capacity << ",size="<< this->size<< std::endl; + +#endif Number result; + Number temp; int i; - char carry = 0; - int max_size = size > a.size ? size : a.size; - - result.capacity = max_size + 1; - result.data = new char[capacity]; - - for (i = 0; i < max_size; ++i) { + int carry = 0; + if (size < a.size) { + temp = *this; + *this = a; + a = temp; + } + result.capacity = size + 1; + //result.data = new char[capacity]; + result.data = (char*)calloc(result.capacity, sizeof(char)); + for (i = 0; i < a.size; ++i) { result.data[i] = (data[i] + a.data[i] + carry) % base; carry = (data[i] + a.data[i] + carry) / base; } - + for (; i < size; ++i) { + result.data[i] = (data[i] + carry) % base; + carry = (data[i] + carry) / base; + } if (carry) { +#ifdef _DEBUG_ADD + std::cout << "applied carry" << std::endl; +#endif result.data[i] = carry; - result.size = max_size + 1; + result.size = size + 1; } else { - result.size = max_size; + result.size = size; } +#ifdef _DEBUG_ADD + std::cout << result << " capacity=" << result.capacity << ",size="<(const Number& a) const { +#ifdef _DEBUG_COMP + std::cout << "comp " << *this << "(size=" << size << ") and " << a << "(size=" << a.size << ")" << std::endl; +#endif + if (size > a.size) { +#ifdef _DEBUG_COMP + std::cout << "size > a.size => true" << std::endl; +#endif + return true; + } + if (size < a.size) { +#ifdef _DEBUG_COMP + std::cout << "size < a.size => false" << std::endl; +#endif + return false; + } + for (int i = size - 1; i >= 0; --i) { + if (data[i] > a.data[i]) { + return true; +#ifdef _DEBUG_COMP + std::cout << static_cast(data[i]) << ">" << static_cast(a.data[i]) << std::endl; +#endif + } + if (data[i] < a.data[i]) { +#ifdef _DEBUG_COMP + std::cout << static_cast(data[i]) << "<" << static_cast(a.data[i]) < a) and (*this != a); + } + void div2() { +#ifdef _DEBUG_DIV2 + std::cout << "n = " << *this << std::endl; +#endif + int carry = 0; + int temp; + for (int i = size - 1; i >= 0; --i) { + temp = data[i] + carry * base; + data[i] = temp / 2; + carry = temp % 2; + } + if (data[size-1] == 0) { + --size; + } +#ifdef _DEBUG_DIV2 + std::cout << "unstripped result "<< *this << std::endl; +#endif + } + friend std::ostream& operator<<(std::ostream& stream, const Number& right); friend int main(); friend Number factorial(int n); @@ -279,11 +368,39 @@ Number factorial(int n) { return result; } +void grad(Number n) { + + std::cout << "n = " << n; + Number max = n; + unsigned long long int steps = 0; + while (n != Number(1)) { + //std::cout << steps << ":" << n << std::endl; + if (n > max) { +#ifdef _DEBUG_COMP + std::cout << n << " is greater than " << max << std::endl; +#endif + max = n; + } + if (n.isEven()) { + n.div2(); + } + else { + n = Number(3) * n + Number(1); + } + //if(steps > 100) { + // std::cout << "break" << std::endl; + // break; + //} + ++steps; + } + std::cout << " steps = " << steps << " max = " << max << std::endl; +} + int main() { - Number x = Number("25852016738884976640000"); - Number y = Number("24"); - + Number x = Number("12"); + Number y = Number("122"); + //y.div2(); //char s[3]; //Number result = "1"; //for (int i = 1; i < 26; ++i) { @@ -298,10 +415,13 @@ int main() //y = factorial(5); //std::cout << x << " " << x.capacity << " " << x.size << std::endl; //std::cout << y << " "<< y.capacity << " " << y.size << std::endl; - // 90405070506200618121707-18-13-05-18-08 //std::cout << "===" << std::endl << Number(2) * Number(3) << " "<< Number(3) * Number(2) << std::endl; //std::cout << "5! = " << Number(2) * Number(3) * Number(4) * Number(5) << std::endl; - std::cout << factorial(1000) << std::endl; + //std::cout << factorial(1000) << std::endl; //std::cout << Number("620448401733239439360000") * Number(25) << std::endl; + //std::cout << (y < x) << std::endl; + grad(Number("4761963248413673697")); + //grad(Number("256")); + //std::cout << Number(128) * Number(3) + Number(1) + Number(2) + Number(3) + Number(4) << std::endl; } From f0499e0d8c6e38f2b95d51de2f2c4cd9048d6029 Mon Sep 17 00:00:00 2001 From: nihonium Date: Thu, 15 Sep 2022 08:40:48 +0300 Subject: [PATCH 2/3] number splitted, not indented --- .../homework/code/1number/main.cpp | 368 +----------------- .../homework/code/1number/number.cpp | 299 ++++++++++++++ .../homework/code/1number/number.h | 63 +++ 3 files changed, 371 insertions(+), 359 deletions(-) create mode 100644 seminar02_encapsulation/homework/code/1number/number.cpp create mode 100644 seminar02_encapsulation/homework/code/1number/number.h diff --git a/seminar02_encapsulation/homework/code/1number/main.cpp b/seminar02_encapsulation/homework/code/1number/main.cpp index d4a4158..ffbdd2e 100644 --- a/seminar02_encapsulation/homework/code/1number/main.cpp +++ b/seminar02_encapsulation/homework/code/1number/main.cpp @@ -1,347 +1,8 @@ #include #include -#include #include #include - -/* - Класс Number -- класс положительных больших чисел - - Большое число будет храниться в динамическом массиве data - Каждый элемент этого массива содержит разряд числа в 100-ричной системе счисления - (так как base = 100) - По сути, каждый элемент data хранит две цифры числа в десятичной записи - - Значение 100 для системы счисления выбрано как компромис между - эффективностью и удобством написания программы. - Если выбрать значения базы 10 - то программа будет не так эффективна по памяти - Если выбрать значения базы 256 (максимально эффективное использование памяти для типа char), - то алгоритм печати на экран сильно усложнится - В качестве альтернативы, можно было выбрать базу 1e9, - изменив при этом тип элементов c char на int - - capacity - размер массива data - size - сколько ячеек занимет число в массиве data - size <= capacity - - Для удобства разряды числа хранятся в обратном порядке - Например, число 12345678 соответствует массиву - data = {78, 56, 34, 12} - (это упрощает многие алгоритмы с такими числами) -*/ - - -class Number -{ -private: - static const int base = 100; - std::size_t size; - std::size_t capacity; - char* data; - -public: - - Number(int a) - { -#ifdef _DEBUG_CONSTRUCTOR - std::cout << "(Number constructor " << a << " -> "; -#endif - // Находим размер необходимой памяти под это число - int temp = a; - capacity = 0; - while (temp != 0) - { - temp /= base; - capacity += 1; - } - - // Отдельно обрабатываем случай, когда число равно 0 - if (capacity == 0) - capacity = 1; - - // Выделяем память и записывем число a в массив data - // Например, число 12345678 представится в виде массива [78, 56, 34, 12] - - data = new char[capacity]; - - for (int i = 0; i < capacity; ++i) - { - data[i] = a % base; - a /= base; - } - - // В данном случае размер будет равен вместимости - size = capacity; -#ifdef _DEBUG_CONSTRUCTOR - std::cout << *this << ")" << std::endl; -#endif - } - // Конструктор по умолчанию - Number() : Number(0) {} - // Конструктор копирования - Number(const Number& n) { - size = n.size; - capacity = n.capacity; - data = new char[capacity]; - for (int i = 0; i < size; i++) { - data[i] = n.data[i]; - } - } - Number(const char* str) { - int len = std::strlen(str); - size = (len + len % 2) / 2; - capacity = size; - data = new char[capacity]; - char buf[2]; - for (int i = 0; i < size; i++) { - buf[1] = str[len - 2 * i - 1]; - if (len - 2 * i - 1 > 0) { - buf[0] = str[len - 2 * i - 2]; - } - else { - buf[0] = '0'; - } - data[i] = std::stoi(buf); - } - } - ~Number() - { - delete [] data; - } - Number& operator=(const Number& right) { - capacity = right.capacity; - size = right.size; - data = new char[capacity]; - for (int i = 0; i < size; i++) { - data[i] = right.data[i]; - } - return *this; - } - - Number operator+(Number a) { -#ifdef _DEBUG_ADD - std::cout << "arg1=" << a << "capacity=" << a.capacity << ",size="<< a.size<< std::endl; - std::cout << "arg2=" << *this << "capacity=" << this->capacity << ",size="<< this->size<< std::endl; - -#endif - Number result; - Number temp; - int i; - int carry = 0; - if (size < a.size) { - temp = *this; - *this = a; - a = temp; - } - result.capacity = size + 1; - //result.data = new char[capacity]; - result.data = (char*)calloc(result.capacity, sizeof(char)); - for (i = 0; i < a.size; ++i) { - result.data[i] = (data[i] + a.data[i] + carry) % base; - carry = (data[i] + a.data[i] + carry) / base; - } - for (; i < size; ++i) { - result.data[i] = (data[i] + carry) % base; - carry = (data[i] + carry) / base; - } - if (carry) { -#ifdef _DEBUG_ADD - std::cout << "applied carry" << std::endl; -#endif - result.data[i] = carry; - result.size = size + 1; - } - else { - result.size = size; - } -#ifdef _DEBUG_ADD - std::cout << result << " capacity=" << result.capacity << ",size="<(result.data[i + j]) << " + " << static_cast(data[i]) << " * " << static_cast(right.data[j]) << " + " << carry[i+j] << std::endl; -#endif - temp = (result.data[i + j] + data[i] * right.data[j] + carry[i + j]); - result.data[i + j] = temp % base; - carry[i + j + 1] += temp / base; - carry[i + j] = 0; - - } - } -#ifdef _DEBUG_MUL - std::cout << "result before applying carry:" << result << std::endl; - std::cout << "carry:[" << carry[0]; - for (int k = 1; k < result.capacity; ++k) { - std::cout << "," << carry[k]; - } - std::cout << "]" << std::endl; -#endif - if (carry[i + j - 1]) { - result.data[i + j - 1] = carry[i + j - 1]; - result.size = i + j; - } - else { - result.size = i + j - 1; - } - -#ifdef _DEBUG_MUL - std::cout << "before correcting capacity, result=" << result << std::endl; -#endif - // correcting capacity - /*char* temp_data = (char *)calloc(result.size, sizeof(char)); - for (i = 0; i < result.size; ++i) { - temp_data[i] = result.data[i]; - } - - free(result.data); - result.capacity = result.size; - result.data = (char*)calloc(result.size,sizeof(char)); - for (i = 0; i < result.size; ++i) { - result.data[i] = temp_data[i]; - } - - free(temp_data);*/ - free(carry); -#ifdef _DEBUG_MUL - std::cout << "return value=" << result << "(capacity=" << result.capacity << ",size=" << result.size << ")" << std::endl << "======" << std::endl; -#endif - return result; - } - void operator*=(const Number& a) { - *this = *this * a; - } - - bool operator==(const Number& a) const { - if (size != a.size) { - return false; - } - for (int i = 0; i < size; ++i) { - if (data[i] != a.data[i]) { - return false; - } - } - return true; - } - bool operator!=(const Number& a) const { - return not (*this == a); - } - bool operator>(const Number& a) const { -#ifdef _DEBUG_COMP - std::cout << "comp " << *this << "(size=" << size << ") and " << a << "(size=" << a.size << ")" << std::endl; -#endif - if (size > a.size) { -#ifdef _DEBUG_COMP - std::cout << "size > a.size => true" << std::endl; -#endif - return true; - } - if (size < a.size) { -#ifdef _DEBUG_COMP - std::cout << "size < a.size => false" << std::endl; -#endif - return false; - } - for (int i = size - 1; i >= 0; --i) { - if (data[i] > a.data[i]) { - return true; -#ifdef _DEBUG_COMP - std::cout << static_cast(data[i]) << ">" << static_cast(a.data[i]) << std::endl; -#endif - } - if (data[i] < a.data[i]) { -#ifdef _DEBUG_COMP - std::cout << static_cast(data[i]) << "<" << static_cast(a.data[i]) < a) and (*this != a); - } - void div2() { -#ifdef _DEBUG_DIV2 - std::cout << "n = " << *this << std::endl; -#endif - int carry = 0; - int temp; - for (int i = size - 1; i >= 0; --i) { - temp = data[i] + carry * base; - data[i] = temp / 2; - carry = temp % 2; - } - if (data[size-1] == 0) { - --size; - } -#ifdef _DEBUG_DIV2 - std::cout << "unstripped result "<< *this << std::endl; -#endif - } - - friend std::ostream& operator<<(std::ostream& stream, const Number& right); - friend int main(); - friend Number factorial(int n); -}; - - - -std::ostream& operator<<(std::ostream& stream, const Number& right) -{ -#ifdef _DEBUG_COUT - stream << "["; - for (std::size_t i = 0; i < right.size; ++i) { - stream << static_cast(right.data[right.size - 2 - i]) << ","; - } - stream << "]"; -#else - // Печатаем самый большой разряд - stream << (int)right.data[right.size - 1]; - - // Печатаем остальные разряды с заполнением нулями до 2-х цифр - // setfill и setw это то же самое, что и в языке C спецификатор %02d - for (std::size_t i = 0; i < right.size - 1; ++i) - stream << std::setfill('0') << std::setw(2) << (int)right.data[right.size - 2 - i]; -#endif - return stream; -} +#include "number.h" Number fib(int n) { Number a = 0; // F0 @@ -374,7 +35,6 @@ void grad(Number n) { Number max = n; unsigned long long int steps = 0; while (n != Number(1)) { - //std::cout << steps << ":" << n << std::endl; if (n > max) { #ifdef _DEBUG_COMP std::cout << n << " is greater than " << max << std::endl; @@ -387,10 +47,12 @@ void grad(Number n) { else { n = Number(3) * n + Number(1); } - //if(steps > 100) { - // std::cout << "break" << std::endl; - // break; - //} +#ifdef _DEBUG_GRAD + if(steps > 100) { + std::cout << "break" << std::endl; + break; + } +#endif ++steps; } std::cout << " steps = " << steps << " max = " << max << std::endl; @@ -398,19 +60,7 @@ void grad(Number n) { int main() { - Number x = Number("12"); - Number y = Number("122"); - //y.div2(); - //char s[3]; - //Number result = "1"; - //for (int i = 1; i < 26; ++i) { - //s = std::to_string(i); - //sprintf(s, "%d", i); - // result = (Number{i} * result); - //} - //x += y; - //Number z = x + y; - //std::cout << fib(1000) << std::endl; + std::cout << fib(1000) << std::endl; //x = x * Number(24)*Number{25}; //y = factorial(5); //std::cout << x << " " << x.capacity << " " << x.size << std::endl; @@ -420,7 +70,7 @@ int main() //std::cout << factorial(1000) << std::endl; //std::cout << Number("620448401733239439360000") * Number(25) << std::endl; //std::cout << (y < x) << std::endl; - grad(Number("4761963248413673697")); + //grad(Number("4761963248413673697")); //grad(Number("256")); //std::cout << Number(128) * Number(3) + Number(1) + Number(2) + Number(3) + Number(4) << std::endl; } diff --git a/seminar02_encapsulation/homework/code/1number/number.cpp b/seminar02_encapsulation/homework/code/1number/number.cpp new file mode 100644 index 0000000..f1e13de --- /dev/null +++ b/seminar02_encapsulation/homework/code/1number/number.cpp @@ -0,0 +1,299 @@ +#include +#include +#include +#include "number.h" + +Number::Number(int a) + { +#ifdef _DEBUG_CONSTRUCTOR + std::cout << "(Number constructor " << a << " -> "; +#endif + // Находим размер необходимой памяти под это число + int temp = a; + capacity = 0; + while (temp != 0) + { + temp /= base; + capacity += 1; + } + + // Отдельно обрабатываем случай, когда число равно 0 + if (capacity == 0) + capacity = 1; + + // Выделяем память и записывем число a в массив data + // Например, число 12345678 представится в виде массива [78, 56, 34, 12] + + data = new char[capacity]; + + for (int i = 0; i < capacity; ++i) + { + data[i] = a % base; + a /= base; + } + + // В данном случае размер будет равен вместимости + size = capacity; +#ifdef _DEBUG_CONSTRUCTOR + std::cout << *this << ")" << std::endl; +#endif + } +// Конструктор по умолчанию +Number::Number() : Number(0) {} +// Конструктор копирования +Number::Number(const Number& n) { + size = n.size; + capacity = n.capacity; + data = new char[capacity]; + for (int i = 0; i < size; i++) { + data[i] = n.data[i]; + } + } +Number::Number(const char* str) { + int len = std::strlen(str); + size = (len + len % 2) / 2; + capacity = size; + data = new char[capacity]; + char buf[2]; + for (int i = 0; i < size; i++) { + buf[1] = str[len - 2 * i - 1]; + if (len - 2 * i - 1 > 0) { + buf[0] = str[len - 2 * i - 2]; + } + else { + buf[0] = '0'; + } + data[i] = std::stoi(buf); + } + } +Number::~Number() + { + delete [] data; + } +Number& Number::operator=(const Number& right) { + capacity = right.capacity; + size = right.size; + data = new char[capacity]; + for (int i = 0; i < size; i++) { + data[i] = right.data[i]; + } + return *this; + } + +Number Number::operator+(Number a) { +#ifdef _DEBUG_ADD + std::cout << "arg1=" << a << "capacity=" << a.capacity << ",size="<< a.size<< std::endl; + std::cout << "arg2=" << *this << "capacity=" << this->capacity << ",size="<< this->size<< std::endl; + +#endif + Number result; + Number temp; + int i; + int carry = 0; + if (size < a.size) { + temp = *this; + *this = a; + a = temp; + } + result.capacity = size + 1; + //result.data = new char[capacity]; + result.data = (char*)calloc(result.capacity, sizeof(char)); + for (i = 0; i < a.size; ++i) { + result.data[i] = (data[i] + a.data[i] + carry) % base; + carry = (data[i] + a.data[i] + carry) / base; + } + for (; i < size; ++i) { + result.data[i] = (data[i] + carry) % base; + carry = (data[i] + carry) / base; + } + if (carry) { +#ifdef _DEBUG_ADD + std::cout << "applied carry" << std::endl; +#endif + result.data[i] = carry; + result.size = size + 1; + } + else { + result.size = size; + } +#ifdef _DEBUG_ADD + std::cout << result << " capacity=" << result.capacity << ",size="<(result.data[i + j]) << " + " << static_cast(data[i]) << " * " << static_cast(right.data[j]) << " + " << carry[i+j] << std::endl; +#endif + temp = (result.data[i + j] + data[i] * right.data[j] + carry[i + j]); + result.data[i + j] = temp % base; + carry[i + j + 1] += temp / base; + carry[i + j] = 0; + + } + } +#ifdef _DEBUG_MUL + std::cout << "result before applying carry:" << result << std::endl; + std::cout << "carry:[" << carry[0]; + for (int k = 1; k < result.capacity; ++k) { + std::cout << "," << carry[k]; + } + std::cout << "]" << std::endl; +#endif + if (carry[i + j - 1]) { + result.data[i + j - 1] = carry[i + j - 1]; + result.size = i + j; + } + else { + result.size = i + j - 1; + } + +#ifdef _DEBUG_MUL + std::cout << "before correcting capacity, result=" << result << std::endl; +#endif + // correcting capacity + /*char* temp_data = (char *)calloc(result.size, sizeof(char)); + for (i = 0; i < result.size; ++i) { + temp_data[i] = result.data[i]; + } + + free(result.data); + result.capacity = result.size; + result.data = (char*)calloc(result.size,sizeof(char)); + for (i = 0; i < result.size; ++i) { + result.data[i] = temp_data[i]; + } + + free(temp_data);*/ + free(carry); +#ifdef _DEBUG_MUL + std::cout << "return value=" << result << "(capacity=" << result.capacity << ",size=" << result.size << ")" << std::endl << "======" << std::endl; +#endif + return result; + } +void Number::operator*=(const Number& a) { + *this = *this * a; + } + +bool Number::operator==(const Number& a) const { + if (size != a.size) { + return false; + } + for (int i = 0; i < size; ++i) { + if (data[i] != a.data[i]) { + return false; + } + } + return true; + } +bool Number::operator!=(const Number& a) const { + return not (*this == a); + } +bool Number::operator>(const Number& a) const { +#ifdef _DEBUG_COMP + std::cout << "comp " << *this << "(size=" << size << ") and " << a << "(size=" << a.size << ")" << std::endl; +#endif + if (size > a.size) { +#ifdef _DEBUG_COMP + std::cout << "size > a.size => true" << std::endl; +#endif + return true; + } + if (size < a.size) { +#ifdef _DEBUG_COMP + std::cout << "size < a.size => false" << std::endl; +#endif + return false; + } + for (int i = size - 1; i >= 0; --i) { + if (data[i] > a.data[i]) { + return true; +#ifdef _DEBUG_COMP + std::cout << static_cast(data[i]) << ">" << static_cast(a.data[i]) << std::endl; +#endif + } + if (data[i] < a.data[i]) { +#ifdef _DEBUG_COMP + std::cout << static_cast(data[i]) << "<" << static_cast(a.data[i]) < a) and (*this != a); + } +void Number::div2() { +#ifdef _DEBUG_DIV2 + std::cout << "n = " << *this << std::endl; +#endif + int carry = 0; + int temp; + for (int i = size - 1; i >= 0; --i) { + temp = data[i] + carry * base; + data[i] = temp / 2; + carry = temp % 2; + } + if (data[size-1] == 0) { + --size; + } +#ifdef _DEBUG_DIV2 + std::cout << "unstripped result "<< *this << std::endl; +#endif + } + + +std::ostream& operator<<(std::ostream& stream, const Number& right) +{ +#ifdef _DEBUG_COUT + stream << "["; + for (std::size_t i = 0; i < right.size; ++i) { + stream << static_cast(right.data[right.size - 2 - i]) << ","; + } + stream << "]"; +#else + // Печатаем самый большой разряд + stream << (int)right.data[right.size - 1]; + + // Печатаем остальные разряды с заполнением нулями до 2-х цифр + // setfill и setw это то же самое, что и в языке C спецификатор %02d + for (std::size_t i = 0; i < right.size - 1; ++i) + stream << std::setfill('0') << std::setw(2) << (int)right.data[right.size - 2 - i]; +#endif + return stream; +} diff --git a/seminar02_encapsulation/homework/code/1number/number.h b/seminar02_encapsulation/homework/code/1number/number.h new file mode 100644 index 0000000..f73c2be --- /dev/null +++ b/seminar02_encapsulation/homework/code/1number/number.h @@ -0,0 +1,63 @@ +#pragma once +/* + Класс Number -- класс положительных больших чисел + + Большое число будет храниться в динамическом массиве data + Каждый элемент этого массива содержит разряд числа в 100-ричной системе счисления + (так как base = 100) + По сути, каждый элемент data хранит две цифры числа в десятичной записи + + Значение 100 для системы счисления выбрано как компромис между + эффективностью и удобством написания программы. + Если выбрать значения базы 10 - то программа будет не так эффективна по памяти + Если выбрать значения базы 256 (максимально эффективное использование памяти для типа char), + то алгоритм печати на экран сильно усложнится + В качестве альтернативы, можно было выбрать базу 1e9, + изменив при этом тип элементов c char на int + + capacity - размер массива data + size - сколько ячеек занимет число в массиве data + size <= capacity + + Для удобства разряды числа хранятся в обратном порядке + Например, число 12345678 соответствует массиву + data = {78, 56, 34, 12} + (это упрощает многие алгоритмы с такими числами) +*/ + +class Number +{ +private: + static const int base = 100; + std::size_t size; + std::size_t capacity; + char* data; + +public: + + Number(int a); + Number(); + // Конструктор копирования + Number(const Number& n); + Number(const char* str); + ~Number(); + Number& operator=(const Number& right); + + Number operator+(Number a); + void operator+=(const Number& a); + + bool isEven() const; + + Number operator*(const Number& right) const; + void operator*=(const Number& a); + + bool operator==(const Number& a) const; + bool operator!=(const Number& a) const; + bool operator>(const Number& a) const; + bool operator<(const Number& a) const; + void div2(); + + friend std::ostream& operator<<(std::ostream& stream, const Number& right); +}; + +std::ostream& operator<<(std::ostream& stream, const Number& right); From c495b7c47f944f0167667e16d03570a838ee7064 Mon Sep 17 00:00:00 2001 From: nihonium Date: Thu, 15 Sep 2022 10:29:14 +0300 Subject: [PATCH 3/3] number final --- .../homework/code/1number/main.cpp | 90 ++- .../homework/code/1number/number.cpp | 520 ++++++++++-------- .../homework/code/1number/number.h | 42 +- 3 files changed, 346 insertions(+), 306 deletions(-) diff --git a/seminar02_encapsulation/homework/code/1number/main.cpp b/seminar02_encapsulation/homework/code/1number/main.cpp index ffbdd2e..c394d6f 100644 --- a/seminar02_encapsulation/homework/code/1number/main.cpp +++ b/seminar02_encapsulation/homework/code/1number/main.cpp @@ -4,74 +4,72 @@ #include #include "number.h" -Number fib(int n) { - Number a = 0; // F0 - Number b = 1; // F1 - for (int i = 1; i <=n; ++i) { - if (i % 2) { - a += b; - } - else { - b += a; - } +Number fib(int n) +{ + Number a = 0; // F0 + Number b = 1; // F1 + for (int i = 1; i <= n; ++i) { + if (i % 2) { + a += b; + } else { + b += a; + } } if (n % 2) { - return b; + return b; } return a; } -Number factorial(int n) { - Number result{1}; +Number factorial(int n) +{ + Number result { + 1}; for (int i = 2; i < n + 1; ++i) { - result = Number(i) * result; + result = Number(i) * result; } return result; } -void grad(Number n) { +void grad(Number n) +{ std::cout << "n = " << n; Number max = n; unsigned long long int steps = 0; while (n != Number(1)) { - if (n > max) { + if (n > max) { #ifdef _DEBUG_COMP - std::cout << n << " is greater than " << max << std::endl; + std::cout << n << " is greater than " << max << std::endl; #endif - max = n; - } - if (n.isEven()) { - n.div2(); - } - else { - n = Number(3) * n + Number(1); - } + max = n; + } + if (n.isEven()) { + n.div2(); + } else { + n = Number(3) * n + Number(1); + } #ifdef _DEBUG_GRAD - if(steps > 100) { - std::cout << "break" << std::endl; - break; - } + if (steps > 100) { + std::cout << "break" << std::endl; + break; + } #endif - ++steps; + ++steps; } - std::cout << " steps = " << steps << " max = " << max << std::endl; + std::cout << " steps = " << steps << " max = " << max << std::endl; } -int main() +int main() { - std::cout << fib(1000) << std::endl; - //x = x * Number(24)*Number{25}; - //y = factorial(5); - //std::cout << x << " " << x.capacity << " " << x.size << std::endl; - //std::cout << y << " "<< y.capacity << " " << y.size << std::endl; - //std::cout << "===" << std::endl << Number(2) * Number(3) << " "<< Number(3) * Number(2) << std::endl; - //std::cout << "5! = " << Number(2) * Number(3) * Number(4) * Number(5) << std::endl; - //std::cout << factorial(1000) << std::endl; - //std::cout << Number("620448401733239439360000") * Number(25) << std::endl; - //std::cout << (y < x) << std::endl; - //grad(Number("4761963248413673697")); - //grad(Number("256")); - //std::cout << Number(128) * Number(3) + Number(1) + Number(2) + Number(3) + Number(4) << std::endl; + std::cout << "===FIB===" << std::endl; + std::cout << "F(1000) = " << fib(1000) << std::endl; + std::cout << "===FAC===" << std::endl; + std::cout << "1000! = " << factorial(1000) << std::endl; + std::cout << "===GRAD===" << std::endl; + grad(Number("7")); + grad(Number("256")); + grad(Number("1117065")); + grad(Number("4761963248413673697")); + grad(Number("90560792656972947582439785608972465789628974587264056284658721771")); } - diff --git a/seminar02_encapsulation/homework/code/1number/number.cpp b/seminar02_encapsulation/homework/code/1number/number.cpp index f1e13de..1950874 100644 --- a/seminar02_encapsulation/homework/code/1number/number.cpp +++ b/seminar02_encapsulation/homework/code/1number/number.cpp @@ -3,297 +3,339 @@ #include #include "number.h" -Number::Number(int a) - { +Number::Number(int a) +{ #ifdef _DEBUG_CONSTRUCTOR - std::cout << "(Number constructor " << a << " -> "; -#endif - // Находим размер необходимой памяти под это число - int temp = a; - capacity = 0; - while (temp != 0) - { - temp /= base; - capacity += 1; - } - - // Отдельно обрабатываем случай, когда число равно 0 - if (capacity == 0) - capacity = 1; - - // Выделяем память и записывем число a в массив data - // Например, число 12345678 представится в виде массива [78, 56, 34, 12] - - data = new char[capacity]; - - for (int i = 0; i < capacity; ++i) - { - data[i] = a % base; - a /= base; - } - - // В данном случае размер будет равен вместимости - size = capacity; -#ifdef _DEBUG_CONSTRUCTOR - std::cout << *this << ")" << std::endl; + std::cout << "(Number constructor " << a << " -> "; #endif + // Находим размер необходимой памяти под это число + int temp = a; + capacity = 0; + while (temp != 0) { + temp /= base; + capacity += 1; } + + // Отдельно обрабатываем случай, когда число равно 0 + if (capacity == 0) + capacity = 1; + + // Выделяем память и записывем число a в массив data + // Например, число 12345678 представится в виде массива [78, 56, 34, 12] + + data = new char[capacity]; + + for (int i = 0; i < capacity; ++i) { + data[i] = a % base; + a /= base; + } + + // В данном случае размер будет равен вместимости + size = capacity; +#ifdef _DEBUG_CONSTRUCTOR + std::cout << *this << ")" << std::endl; +#endif +} + // Конструктор по умолчанию -Number::Number() : Number(0) {} +Number::Number():Number(0){} + // Конструктор копирования -Number::Number(const Number& n) { - size = n.size; - capacity = n.capacity; - data = new char[capacity]; - for (int i = 0; i < size; i++) { - data[i] = n.data[i]; - } - } -Number::Number(const char* str) { - int len = std::strlen(str); - size = (len + len % 2) / 2; - capacity = size; - data = new char[capacity]; - char buf[2]; - for (int i = 0; i < size; i++) { - buf[1] = str[len - 2 * i - 1]; - if (len - 2 * i - 1 > 0) { - buf[0] = str[len - 2 * i - 2]; - } - else { - buf[0] = '0'; - } - data[i] = std::stoi(buf); - } - } -Number::~Number() - { - delete [] data; - } -Number& Number::operator=(const Number& right) { - capacity = right.capacity; - size = right.size; - data = new char[capacity]; - for (int i = 0; i < size; i++) { - data[i] = right.data[i]; - } - return *this; +Number::Number(const Number & n) +{ + size = n.size; + capacity = n.capacity; + data = new char[capacity]; + for (int i = 0; i < size; i++) { + data[i] = n.data[i]; } +} -Number Number::operator+(Number a) { +Number::Number(const char *str) +{ + int len = std::strlen(str); + size = (len + len % 2) / 2; + capacity = size; + data = new char[capacity]; + char buf[2]; + for (int i = 0; i < size; i++) { + buf[1] = str[len - 2 * i - 1]; + if (len - 2 * i - 1 > 0) { + buf[0] = str[len - 2 * i - 2]; + } else { + buf[0] = '0'; + } + data[i] = std::stoi(buf); + } +} + +Number::~Number() +{ + delete[]data; +} + +Number & Number::operator=(const Number & right) +{ + capacity = right.capacity; + size = right.size; + data = new char[capacity]; + for (int i = 0; i < size; i++) { + data[i] = right.data[i]; + } + return *this; +} + +Number Number::operator+(Number a) +{ #ifdef _DEBUG_ADD - std::cout << "arg1=" << a << "capacity=" << a.capacity << ",size="<< a.size<< std::endl; - std::cout << "arg2=" << *this << "capacity=" << this->capacity << ",size="<< this->size<< std::endl; + std::cout << "arg1=" << a << "capacity=" << a. + capacity << ",size=" << a.size << std::endl; + std::cout << "arg2=" << *this << "capacity=" << this-> + capacity << ",size=" << this->size << std::endl; #endif - Number result; - Number temp; - int i; - int carry = 0; - if (size < a.size) { - temp = *this; - *this = a; - a = temp; - } - result.capacity = size + 1; - //result.data = new char[capacity]; - result.data = (char*)calloc(result.capacity, sizeof(char)); - for (i = 0; i < a.size; ++i) { - result.data[i] = (data[i] + a.data[i] + carry) % base; - carry = (data[i] + a.data[i] + carry) / base; - } - for (; i < size; ++i) { - result.data[i] = (data[i] + carry) % base; - carry = (data[i] + carry) / base; - } - if (carry) { -#ifdef _DEBUG_ADD - std::cout << "applied carry" << std::endl; -#endif - result.data[i] = carry; - result.size = size + 1; - } - else { - result.size = size; - } -#ifdef _DEBUG_ADD - std::cout << result << " capacity=" << result.capacity << ",size="<(result.data[i + j]) << " + " << static_cast(data[i]) << " * " << static_cast(right.data[j]) << " + " << carry[i+j] << std::endl; + std::cout << i + j << ":" << static_cast < + int >(result.data[i + j]) << " + " << static_cast < + int >(data[i]) << " * " << static_cast < + int >(right.data[j]) << " + " << carry[i + j] << std::endl; #endif - temp = (result.data[i + j] + data[i] * right.data[j] + carry[i + j]); - result.data[i + j] = temp % base; - carry[i + j + 1] += temp / base; - carry[i + j] = 0; + temp = + (result.data[i + j] + data[i] * right.data[j] + + carry[i + j]); + result.data[i + j] = temp % base; + carry[i + j + 1] += temp / base; + carry[i + j] = 0; - } - } + } + } #ifdef _DEBUG_MUL - std::cout << "result before applying carry:" << result << std::endl; - std::cout << "carry:[" << carry[0]; - for (int k = 1; k < result.capacity; ++k) { - std::cout << "," << carry[k]; - } - std::cout << "]" << std::endl; + std::cout << "result before applying carry:" << result << std::endl; + std::cout << "carry:[" << carry[0]; + for (int k = 1; k < result.capacity; ++k) { + std::cout << "," << carry[k]; + } + std::cout << "]" << std::endl; #endif - if (carry[i + j - 1]) { - result.data[i + j - 1] = carry[i + j - 1]; - result.size = i + j; - } - else { - result.size = i + j - 1; - } - + if (carry[i + j - 1]) { + result.data[i + j - 1] = carry[i + j - 1]; + result.size = i + j; + } else { + result.size = i + j - 1; + } + #ifdef _DEBUG_MUL - std::cout << "before correcting capacity, result=" << result << std::endl; + std::cout << "before correcting capacity, result=" << result << std:: + endl; #endif - // correcting capacity - /*char* temp_data = (char *)calloc(result.size, sizeof(char)); - for (i = 0; i < result.size; ++i) { - temp_data[i] = result.data[i]; - } + // correcting capacity + /*char* temp_data = (char *)calloc(result.size, sizeof(char)); + for (i = 0; i < result.size; ++i) { + temp_data[i] = result.data[i]; + } - free(result.data); - result.capacity = result.size; - result.data = (char*)calloc(result.size,sizeof(char)); - for (i = 0; i < result.size; ++i) { - result.data[i] = temp_data[i]; - } + free(result.data); + result.capacity = result.size; + result.data = (char*)calloc(result.size,sizeof(char)); + for (i = 0; i < result.size; ++i) { + result.data[i] = temp_data[i]; + } - free(temp_data);*/ - free(carry); + free(temp_data); */ + free(carry); #ifdef _DEBUG_MUL - std::cout << "return value=" << result << "(capacity=" << result.capacity << ",size=" << result.size << ")" << std::endl << "======" << std::endl; + std::cout << "return value=" << result << "(capacity=" << result. + capacity << ",size=" << result. + size << ")" << std::endl << "======" << std::endl; #endif - return result; - } -void Number::operator*=(const Number& a) { - *this = *this * a; - } + return result; +} -bool Number::operator==(const Number& a) const { - if (size != a.size) { - return false; - } - for (int i = 0; i < size; ++i) { - if (data[i] != a.data[i]) { - return false; - } - } - return true; - } -bool Number::operator!=(const Number& a) const { - return not (*this == a); - } -bool Number::operator>(const Number& a) const { -#ifdef _DEBUG_COMP - std::cout << "comp " << *this << "(size=" << size << ") and " << a << "(size=" << a.size << ")" << std::endl; -#endif - if (size > a.size) { -#ifdef _DEBUG_COMP - std::cout << "size > a.size => true" << std::endl; -#endif - return true; - } - if (size < a.size) { -#ifdef _DEBUG_COMP - std::cout << "size < a.size => false" << std::endl; -#endif - return false; - } - for (int i = size - 1; i >= 0; --i) { - if (data[i] > a.data[i]) { - return true; -#ifdef _DEBUG_COMP - std::cout << static_cast(data[i]) << ">" << static_cast(a.data[i]) << std::endl; -#endif - } - if (data[i] < a.data[i]) { -#ifdef _DEBUG_COMP - std::cout << static_cast(data[i]) << "<" << static_cast(a.data[i]) <(const Number & a) const +{ #ifdef _DEBUG_COMP - std::cout << "using final false" << std::endl; + std:: + cout << "comp " << *this << "(size=" << size << ") and " << a << + "(size=" << a.size << ")" << std::endl; #endif - return false; + if (size > a.size) { +#ifdef _DEBUG_COMP + std::cout << "size > a.size => true" << std::endl; +#endif + return true; } -bool Number::operator<(const Number& a) const { - return not (*this > a) and (*this != a); + if (size < a.size) { +#ifdef _DEBUG_COMP + std::cout << "size < a.size => false" << std::endl; +#endif + return false; } -void Number::div2() { + for (int i = size - 1; i >= 0; --i) { + if (data[i] > a.data[i]) { + return true; +#ifdef _DEBUG_COMP + std::cout << static_cast < + int >(data[i]) << ">" << static_cast < + int >(a.data[i]) << std::endl; +#endif + } + if (data[i] < a.data[i]) { +#ifdef _DEBUG_COMP + std::cout << static_cast < + int >(data[i]) << "<" << static_cast < + int >(a.data[i]) << std::endl; +#endif + return false; + } + + } +#ifdef _DEBUG_COMP + std::cout << "using final false" << std::endl; +#endif + return false; +} + +bool Number::operator<(const Number & a) const +{ + return not(*this > a) and(*this != a); +} + +void Number::div2() +{ #ifdef _DEBUG_DIV2 - std::cout << "n = " << *this << std::endl; -#endif - int carry = 0; - int temp; - for (int i = size - 1; i >= 0; --i) { - temp = data[i] + carry * base; - data[i] = temp / 2; - carry = temp % 2; - } - if (data[size-1] == 0) { - --size; - } -#ifdef _DEBUG_DIV2 - std::cout << "unstripped result "<< *this << std::endl; + std::cout << "n = " << *this << std::endl; #endif + int carry = 0; + int temp; + for (int i = size - 1; i >= 0; --i) { + temp = data[i] + carry * base; + data[i] = temp / 2; + carry = temp % 2; } + if (data[size - 1] == 0) { + --size; + } +#ifdef _DEBUG_DIV2 + std::cout << "unstripped result " << *this << std::endl; +#endif +} -std::ostream& operator<<(std::ostream& stream, const Number& right) +std::ostream & operator<<(std::ostream & stream, const Number & right) { #ifdef _DEBUG_COUT stream << "["; for (std::size_t i = 0; i < right.size; ++i) { - stream << static_cast(right.data[right.size - 2 - i]) << ","; + stream << static_cast < + int >(right.data[right.size - 2 - i]) << ","; } stream << "]"; #else - // Печатаем самый большой разряд - stream << (int)right.data[right.size - 1]; + // Печатаем самый большой разряд + stream << (int) right.data[right.size - 1]; // Печатаем остальные разряды с заполнением нулями до 2-х цифр // setfill и setw это то же самое, что и в языке C спецификатор %02d for (std::size_t i = 0; i < right.size - 1; ++i) - stream << std::setfill('0') << std::setw(2) << (int)right.data[right.size - 2 - i]; + stream << std::setfill('0') << std::setw(2) << (int) right. + data[right.size - 2 - i]; #endif return stream; } diff --git a/seminar02_encapsulation/homework/code/1number/number.h b/seminar02_encapsulation/homework/code/1number/number.h index f73c2be..fb78011 100644 --- a/seminar02_encapsulation/homework/code/1number/number.h +++ b/seminar02_encapsulation/homework/code/1number/number.h @@ -25,39 +25,39 @@ (это упрощает многие алгоритмы с такими числами) */ -class Number -{ -private: +class Number { + private: static const int base = 100; - std::size_t size; - std::size_t capacity; - char* data; + std::size_t size; + std::size_t capacity; + char *data; -public: + public: - Number(int a); - Number(); + Number(int a); + Number(); // Конструктор копирования - Number(const Number& n); - Number(const char* str); + Number(const Number & n); + Number(const char *str); ~Number(); - Number& operator=(const Number& right); + Number & operator=(const Number & right); Number operator+(Number a); - void operator+=(const Number& a); + void operator+=(const Number & a); bool isEven() const; - Number operator*(const Number& right) const; - void operator*=(const Number& a); + Number operator*(const Number & right) const; + void operator*=(const Number & a); - bool operator==(const Number& a) const; - bool operator!=(const Number& a) const; - bool operator>(const Number& a) const; - bool operator<(const Number& a) const; + bool operator==(const Number & a) const; + bool operator!=(const Number & a) const; + bool operator>(const Number & a) const; + bool operator<(const Number & a) const; void div2(); - friend std::ostream& operator<<(std::ostream& stream, const Number& right); + friend std::ostream & operator<<(std::ostream & stream, + const Number & right); }; -std::ostream& operator<<(std::ostream& stream, const Number& right); +std::ostream & operator<<(std::ostream & stream, const Number & right);