Задача - создать класс рациональной дроби - Rational -, числитель и знаменатель которой - массивы типа unsigned char фиксированного размера. Определить операции сложения, вычитания, умножения, деления и сравнений (>,<,==). Я решил создать вспомогательный класс safeunschar и в нём определить сложение, вычитание и умножение массивов. Потом, на основе этих операций, я определил по заданию действия с дробями.
Проблема в том, что для удобства, операции с массивами могут вызываться из других операций - например, операция вычитания в моём исполнении вычитает только из большего меньшее, иначе вызывается операция вычитания, в которой они меняются местами. Или для сравнения используется операция вычитания между массивами, и по знаку операции возвращается значение. А так как при таких вызовах из операций создаются всё новые и новые объекты в стеке - стек полностью ими выжирается, и программа вылетает.
Пожалуйста, подскажите, как реорганизовать программу, чтобы сэкономит память.
#define _CRT_SECURE_NO_WARNINGS //отключает запрещение компиллятора использовать небезопасные функции по типу strcat(), strcpy, itoa() и т. д.
#include <iostream>
#include <string>
using namespace std;
void itounchar(int value, unsigned char* buf)
{
int size = 0, b = value;
do{ b /= 10; size++; } while (b != 0); //подсчитывается размер числа
buf[size] = '\0'; //на конец числа в массиве ставится нуль-символ
for (size -= 1; size >= 0; size--) //число "задом наперёд" записывается в массив
{
buf[size] = static_cast<char>(value % 10 + 48); //записывается последняя цифра числа (прибавляется 48, так как кодировки int и char различаются на 48)
value /= 10; //последняя цифра числа стирается
}
}
class safeunschar
{
int minus;
static const int fixsize = 100; //static - в любом объекте этого класса size будет равно 100
unsigned char *arr;
int size;
void check()
{
int begzero = 0;
bool check = true;
for (int i = 0; i < size; i++)
{
if (arr[i] != '0')
check = false;
if (check) begzero++;
}
if (check)
{
size = 1;
minus = 1;
}
else if (begzero > 0)
{
for (int a = 0, b = begzero; b < size; b++, a++)
arr[a] = arr[b];
size -= begzero;
}
}
void reverse()
{
unsigned char buf;
for (int a = 0, b = size - 1; a < b; a++, b--)
{
buf = arr[a];
arr[a] = arr[b];
arr[b] = buf;
}
}
public:
safeunschar()
{
minus = 1;
arr = new unsigned char[fixsize];
arr[0] = '0';
size = 1;
}
safeunschar(safeunschar& ob)
{
//cout << "COPY!" << endl;
minus = ob.minus;
arr = new unsigned char[fixsize];
for (int i = 0; i < ob.size; i++)
arr[i] = ob.arr[i];
//cout << arr << endl;
size = ob.size;
}
safeunschar operator*(int a)
{
safeunschar buf;
if (a < 0)
{
buf.minus = -1;
a *= (-1);
}
int high = 0, b;
//cout << "\t\t\t" << endl;//Отладка!
//cout << "\t\t\t" << "Считаем "; this->show(); cout << "\t\t\t * "<<a<<endl;
for (int i = 0, th = this->size - 1; th >= 0; i++, th--)
{
//cout << "\t\t\tДействие " << i << endl;//Отладка!
b = static_cast<int>(this->arr[th] - 48) * a + high;
//cout << "\t\t\t" << "b = " << b << endl;//Отладка!
if (b >= 10)
{
buf.arr[i] = static_cast<char>(b % 10 + 48);
high = b / 10;
}
else
{
buf.arr[i] = static_cast<char>(b + 48);
high = 0;
}
//cout << "\t\t\t" << arr[th] << " * " << a << " = " << buf.arr[i] << endl;//Отладка!
//cout << "\t\t\t" << "high = " << high << endl;//Отладка!
if (i > 0) buf.size++;
}
if (high > 0)
{
/*cout << "\t\t\tВдобавок:" << endl;*/
for (int i = buf.size; high > 0; i++, high /= 10)
{
buf.arr[i] = static_cast<char>(high % 10 + 48);
/*cout << "\t\t\t" << arr[i] << endl;
cout << "\t\t\thigh = " << high / 10 << endl;*/
buf.size++;
}
}
//cout << "неповёрнутый: "; buf.show();
buf.reverse();
//cout << "повёрнутый: "; buf.show();
buf.check();
//cout << "отредактированный: "; buf.show();
return buf;
}
safeunschar operator+(safeunschar& op)
{
safeunschar buf;
int high = 0, b;
if (this->minus == -1 && op.minus == -1) buf.minus = -1;
else if (this->minus == -1)
{
buf = (op - *this*(-1));
return buf;
}
else if (op.minus == -1)
{
buf = (*this - op*(-1));
return buf;
}
// cout << '\t' << endl;//Отладка!
// cout << "\t\t" << "Считаем "; this->show(); cout << "\t\t + "; op.show();
if (this->size < op.size)
{
buf = (op + (*this)); //предполагается, что первый операнд больше, в противном случае они меняются местами
return buf;
}
for (int i = 0, th = this->size - 1, o = op.size - 1; th >= 0; i++, th--, o--)
{
// cout << "\t\tДействие " << i << endl;//Отладка!
if (o < 0)
b = static_cast<int>(this->arr[th]) - 48 + high;
else
b = static_cast<int>(this->arr[th]) - 48 + static_cast<int>(op.arr[o]) - 48 + high;
//cout << "\t\t" << "b = " << b << endl;//Отладка!
if (b >= 10)
{
buf.arr[i] = static_cast<char>(b % 10 + 48);
high = b / 10;
}
else
{
buf.arr[i] = static_cast<char>(b + 48);
high = 0;
}
//cout << "\t\t" << arr[th] << " + " << op.arr[o] << " = " << buf.arr[i] << endl;//Отладка!
//cout << "\t\t" << "high = " << high << endl;//Отладка!
if (i > 0) buf.size++;
}
if (high > 0)
{
//cout << "\t\t\tВдобавок:" << endl;
for (int i = buf.size; high > 0; i++, high /= 10)
{
buf.arr[i] = static_cast<char>(high % 10 + 48);
//cout << "\t\tновый = " << buf.arr[i] << endl;
//cout << "\t\t\thigh = " << high / 10 << endl;
buf.size++;
}
}
//cout << "неповёрнутый: "; buf.show();
buf.reverse();
//cout << "повёрнутый: "; buf.show();
buf.check();
//cout << "отредактированный: "; buf.show();
return buf;
}
safeunschar operator-(safeunschar& op)
{
safeunschar buf;
int c, d, c_next;
if (this->minus == -1 && op.minus == -1)
{
buf = (op*(-1) - *this*(-1));
return buf;
}
else if (this->minus == -1)
{
buf = ((op + *this*(-1))*(-1));
return buf;
}
else if (op.minus == -1)
{
buf = (*this + op*(-1));
return buf;
}
if (this->size < op.size || this->size == op.size)
{
bool flag = false;
for (int i = 0; i < size; i++)
{
if (this->arr[i] < op.arr[i])
flag = true;
}
if (flag)
{
buf = (op - *this);
buf = buf*(-1);
return buf;
}
}
// cout << '\t' << endl;//Отладка!
// cout << "\t" << "Считаем "; this->show(); cout << " - "; op.show(); cout << endl;//Отладка!
c = static_cast<int>(this->arr[this->size - 1]) - 48;
for (int i = 0, th = this->size - 1, o = op.size - 1; th >= 0; i++, th--, o--)
{
if (th != 0)
c_next = static_cast<int>(this->arr[th - 1]) - 48;
if (o >= 0)
d = static_cast<int>(op.arr[o]) - 48;
else
d = 0;
//cout << "Действие " << i << endl;//Отладка!
if (c < d)
{
c_next--;
c += 10;
}
//cout << "\t" << "c = " << c << endl;//Отладка!
//cout << "\t" << "d = " << d << endl;//Отладка!
buf.arr[i] = static_cast<char>(c - d) + 48;
c = c_next;
// cout << "\t" << arr[th] << " - " << op.arr[o] << " = " << buf.arr[i] << endl;//Отладка!
if (i > 0) buf.size++;
}
//cout << "неповёрнутый: "; buf.show();
buf.reverse();
//cout << "повёрнутый: "; buf.show();
buf.check();
//cout << "отредактированный: "; buf.show();
return buf;
}
safeunschar operator*(safeunschar& op)
{
safeunschar buf, sum;
int index = this->minus;
if (this->size < op.size)
return buf = (op*(*this));
//cout << "\tПереданы параметры:" << "\n\ta = "; this->show(); cout << "\n\tb = "; op.show();
for (int o = op.size - 1, th = this->size, i = 0; o >= 0 && th >= 0; o--, th--, i++)
{
//cout << "\tдействие " << i << ". buf = "; buf.show();
//cout << "\tУмножаем " << static_cast<int>(op.arr[o] - 48) * static_cast<int>(pow(10,i)) << " на "; this->show();
//buf = buf + (*this*(index)) * (static_cast<int>(op.arr[o] - 48) * static_cast<int>(pow(10, i)));
sum = (*this*(index)) * (static_cast<int>(op.arr[o] - 48));
for (int j = 0, k = sum.size; j < i; j++, k++)
{
sum.arr[k] = '0';
sum.size++;
}
buf = buf + sum;
}
if (this->minus == -1 && op.minus == -1)
buf.minus = 1;
else if (this->minus == -1 || op.minus == -1)
buf.minus = -1;
else
buf.minus = 1;
buf.check();
return buf;
}
bool operator==(char* s)
{
int sis;
for (sis = 0; s[sis] != '\0'; sis++);
if (sis != size)
return false;
else
{
for (int i = 0; i < size; i++)
{
if (arr[i] != (char)s[i])
return false;
else
return true;
}
}
}
bool operator<(safeunschar& op)
{
safeunschar buf = *this - op;
if (buf.minus > 0 || buf == "0")
return false;
else
return true;
}
bool operator>(safeunschar& op)
{
safeunschar buf = op - *this;
if (buf.minus > 0 || buf == "0")
return false;
else
return true;
}
bool read(string s) //Чтение с клавиатуры
{
//cout << "/tstring: " << s << endl;
if (s.at(0) == '0' && s.length() > 1) return false;
for (int i = 0; i < s.length(); i++)
{
if (((s.at(i)<'0') || (s.at(i)>'9')) && s.at(i) != '-')
return false;
}
if (s.at(0) == '-')
{
minus = -1;
s.erase(0, 1);
}
else
minus = 1;
int n = 0;
for (int i = 0; i < s.length(); i++)
{
arr[n] = (int)s.at(i);
n++;
}
size = n;
return true;
}
void show()
{
//cout << "\n\t size = " << size << "\n";
if (minus == -1)cout << '-';
for (int i = 0; i < size; i++)
cout << arr[i];
}
};
class Rational
{
safeunschar numerator;
safeunschar denomenator;
//void reduce()
//{
// if (!strcmp((char*)numerator, "0")) return;
// int first, second, reduce;
// first = atoi((char*)numerator); //присвоение числителя
// second = atoi((char*)denominator);//присвоениее знаменателя
// while (first != 0 && second != 0) //цикл вычисления наименьшего общего кратного
// {
// if (first >= second) first %= second;
// else second %= first;
// }
// reduce = first + second; //reduce - итоговое наименьшее общее кратное
//
// itounchar(atoi((char*)numerator) / reduce, numerator);
// itounchar(atoi((char*)denominator) / reduce, denominator);
//}
public :
Rational()
{
//числитель и знаменатель инициализируются автоматически
}
void read () //Чтение с клавиатуры
{
string s1,s2;
do {
cout << "Введите числитель: " << endl;
getline(cin,s1);
cout << "Введите знаменатель: " << endl;
getline(cin,s2);
} while ((!numerator.read(s1) || !denomenator.read(s2)) && cout << "Неправильный ввод!" << endl);
}
bool read(string s1,string s2)
{
if (!numerator.read(s1) || !denomenator.read(s2))
return false;
else
return true;
}
void show()
{
numerator.show(); cout << " / "; denomenator.show(); cout << endl;
}
Rational(Rational& ob)
{
this->numerator = ob.numerator;
this->denomenator = ob.denomenator;
}
Rational operator+(Rational op) // op - второй операнд сложения (первый передаётся неявно)
{
Rational buf;
buf.numerator = this->numerator*op.denomenator + op.numerator*this->denomenator;
buf.denomenator = this->numerator*op.denomenator;
return buf;
}
Rational operator-(Rational op)
{
Rational buf;
buf.numerator = this->numerator*op.denomenator - op.numerator*this->denomenator;
buf.denomenator = this->numerator*op.denomenator;
return buf;
}
Rational operator*(Rational op)
{
Rational buf;
buf.numerator = this->numerator*op.numerator;
buf.denomenator = this->numerator*op.denomenator;
return buf;
}
Rational operator/(Rational op)
{
Rational buf; //Результат сложения
if (op.numerator == "0")
{
cout << "Деление на ноль!";
return *this;
}
buf.numerator = this->numerator*op.denomenator;
buf.denomenator = op.numerator*this->denomenator;
return buf;
}
bool operator>(Rational op)
{
if (this->numerator*op.denomenator > op.numerator*this->denomenator)
return true;
else
return false;
}
bool operator<(Rational op)
{
if (this->numerator*op.denomenator < op.numerator*this->denomenator)
return true;
else
return false;
}
/*bool operator==(Rational op)
{
if (this->minus*atoi((char*)this->numerator)*atoi((char*)op.denominator) == op.minus*atoi((char*)op.numerator)*atoi((char*)this->denominator))
return true;
else
return false;
}*/
};
int main()
{
setlocale(0,"rus");
Rational a,b;
string s1, s2;
s1 = "732195927564";
s2 = "151784321267";
a.read(s1,s2);
cout << "a = "; a.show();
s1 = "562736912";
s2 = "115921101";
b.read(s1,s2);
cout << "b = "; b.show();
cout << "a+b = "; (a + b).show();
cout << "a-b = "; (a - b).show();
cout << "a*b = "; (a*b).show();
cout << "a/b = "; (a / b).show();
if (a > b) cout << "a>b" << endl;
else if (a < b) cout << "a<b" << endl;
else cout << "a=b" << endl;
system("pause");
return 0;
}