You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

344 lines
8.1 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <iostream>
#include <iomanip>
#include <cstring>
#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.size << std::endl;
#endif
return result;
}
void Number::operator+=(const Number & a)
{
*this = *this + a;
}
bool Number::isEven() const
{
if (data[0] % 2) {
return false;
}
return true;
}
Number Number::operator*(const Number & right) const
{
#ifdef _DEBUG_MUL
std::
cout << "arg1=" << *this << "(capacity=" << capacity << ",size=" <<
size << ")" << " " << "arg2=" << right << "(capacity=" << right.
capacity << ",size=" << right.size << ")" << std::endl;
#endif
if (*this == Number("0") || right == Number("0"))
return Number("0");
int i, j;
int temp;
Number result;
result.capacity = capacity + right.capacity;
int *carry = (int *) std::calloc(result.capacity, sizeof(int));
result.data = (char *) calloc(result.capacity, sizeof(char));
#ifdef _DEBUG_MUL
std::cout << "carry:[" << carry[0];
for (int k = 1; k < result.capacity; ++k) {
std::cout << "," << carry[k];
}
std::cout << "]" << std::endl;
#endif
for (i = 0; i < size; ++i) {
for (j = 0; j < right.size; ++j) {
#ifdef _DEBUG_MUL
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;
}
}
#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 <
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;
#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 <
int >(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;
}