Добавил:
CanyonE
СПбГУТ * ИКСС * Программная инженерия
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Решения лабораторных работ (местами есть ошибки) / Lab1_Rational numbers (нужно допилить, отрицательные числа не сработают)
.cpp#include <iostream>
#include <cmath>
#include <stdexcept>
using std::cin;
using std::cout;
using std::endl;
// Класс «Рациональное число»
class Rational {
protected:
unsigned long long ulong_abs(long long arg) { // Модуль arg
if (arg < 0) { return -arg; }
return arg;
}
Rational gcdNormalize() { // Нормализация числа при помощи алгоритма Евклида
unsigned long long A = ulong_abs(p), B = ulong_abs(q);
while (A != 0 && B != 0) {
if (A > B) {
A %= B;
} else {
B %= A;
}
}
if (A + B != 0) {
p /= ( A + B ), q /= ( A + B );
} else {
p = 0, q = 1;
}
return *this;
}
public:
long long p, q;
// Конструктор
explicit Rational(long long p = 0, long long q = 1) : p(p), q(q) {
if (q != 0) {
gcdNormalize();
return;
}
throw std::invalid_argument("Q == 0!");
}
// Сложение рациональных чисел
Rational operator+(const Rational &arg) const {
return Rational(p * arg.q + arg.p * q, q * arg.q).gcdNormalize();
}
// Вычитание рациональных чисел
Rational operator-(const Rational &arg) const {
return Rational(p * arg.q - arg.p * q, q * arg.q).gcdNormalize();
}
// Умножение рациональных чисел
Rational operator*(const Rational &arg) const {
Rational temp(p * arg.p, q); // Умножаем только числитель и затем
temp.gcdNormalize(); // Нормализуем число, чтобы уменьшить вероятность переполнения при следующей операции
return Rational(temp.p, temp.q * arg.q).gcdNormalize();
}
// Деление рациональных чисел
Rational operator/(const Rational &arg) const {
Rational temp(p * arg.q, q); // Умножаем только числитель и затем
temp.gcdNormalize(); // Нормализуем число, чтобы уменьшить вероятность переполнения при следующей операции
return Rational(temp.p, temp.q * arg.p).gcdNormalize();
}
// Проверка на равенство
bool operator==(const Rational &arg) const {
return ( toDouble() == arg.toDouble() );
}
// Проверка на неравенство
bool operator!=(const Rational &arg) const {
return ( toDouble() != arg.toDouble() );
}
// Больше
bool operator>(const Rational &arg) const {
return ( toDouble() > arg.toDouble() );
}
// Меньше
bool operator<(const Rational &arg) const {
return ( toDouble() < arg.toDouble() );
}
// Больше или равно
bool operator>=(const Rational &arg) const {
return ( toDouble() >= arg.toDouble() );
}
// Меньше или равно
bool operator<=(const Rational &arg) const {
return ( toDouble() <= arg.toDouble() );
}
// Оператор приведения к типу bool
explicit operator bool() {
return p != 0;
}
// Преобразование в вещественное число
double toDouble() const {
return double(p) / double(q);
}
// Дружественный оператор для вывода рационального числа в выходной поток os (cout, ...)
friend std::ostream &operator<<(std::ostream &os, const Rational &arg) {
return os << arg.p << '/' << arg.q;
}
};
// Рекуррентное соотношение Мюллера. Тест чисел типа Rational и типа Double
void MuellerRecurrenceRatioTest() {
double x0d = 4, x1d = 4.25;
Rational x0r(4, 1), x1r(17, 4);
cout << "I\tDouble\t\tRational\n";
const int N = 13; // N > 13: теряется точность у Rational
for (size_t i = 1; i <= N; ++i) { // Цикл вычисления по Rational и по Double
double tempD = x1d;
x1d = 108. - 815. / x1d + 1500. / x0d / x1d;
x0d = tempD;
Rational tempR = x1r;
x1r = Rational(108) - ( Rational(815) - Rational(1500) / x0r ) / x1r;
x0r = tempR;
cout << i << '\t' << x1d << "\t\t" << x1r.toDouble() << endl;
}
cout << "[Incorrect answer] Double result: " << x1d << endl;
cout << "[Almost correct answer] Rational result: " << x1r << " (" << x1r.toDouble() << ")\n";
}
int main() {
Rational a(2, 3), b(1, 3);
// Простейшие операции с рациональными числами
cout << "A: " << a << " (" << a.toDouble() << ")\n";
cout << "B: " << b << " (" << b.toDouble() << ")\n";
cout << "A + B: " << a + b << " (" << ( a + b ).toDouble() << ")\n";
cout << "A - B: " << a - b << " (" << ( a - b ).toDouble() << ")\n";
cout << "A * B: " << a * b << " (" << ( a * b ).toDouble() << ")\n";
cout << "A / B: " << a / b << " (" << ( a / b ).toDouble() << ")\n";
Rational c(123524, 153524), d(4522, 1232);
cout << "C: " << c << " (" << c.toDouble() << ")\n";
cout << "D: " << d << " (" << d.toDouble() << ")\n";
// Отношения рациональных чисел
cout << "A == B ? " << ( a == b ? "TRUE" : "FALSE" ) << endl;
cout << "A != B ? " << ( a != b ? "TRUE" : "FALSE" ) << endl;
cout << "A > B ? " << ( a > b ? "TRUE" : "FALSE" ) << endl;
cout << "A >= B ? " << ( a >= b ? "TRUE" : "FALSE" ) << endl;
cout << "A < B ? " << ( a < b ? "TRUE" : "FALSE" ) << endl;
cout << "A <= B ? " << ( a <= b ? "TRUE" : "FALSE" ) << endl;
// Рекуррентное соотношение Мюллера
MuellerRecurrenceRatioTest();
}
Соседние файлы в папке Решения лабораторных работ (местами есть ошибки)