#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; } 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 a; } Number factorial(int n) { Number result{1}; for (int i = 2; i < n + 1; ++i) { result = Number(i) * result; } 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("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; //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; }