Класи С ++ можуть створюватися для опису найнесподіваніших сутностей реального світу. Створіть клас «геометрична прогресія», об'єкти якого:
- відображали б геометричну прогресію із заданим початковим членом і знаменником;
- по індексації дозволяли отримати значення члена прогресії з будь-яким порядковим номером;
- дозволяли отримати суму початкових N-членів прогресії;
перезарядка Klass, возможно, іншими корисними властивостями.
Рішення:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #include <iostream> #include <cstdlib> #include <map> using namespace std; class progression : protected pair<double, double> { private: double power(unsigned n) { switch (n) { case 0: return 1.; case 1: return second; default: { double a2 = power(n / 2); a2 *= a2; return n & 1 ? second * a2 : a2; } } } public: progression(double first, double denominator) { this->first = first; second = denominator; } ~progression(void) {} progression(const progression& p) { first = p.first; second = p.second; } progression& operator =(const progression& p) { first = p.first; second = p.second; return *this; } void set(double first, double denominator = 0) { this->first = first; if (denominator != 0) second = denominator; } double operator [](int n) { return first * power(n); } double summa(int n) { double ret = first / second, sum = 0.0; while (--n >= 0) sum += (ret *= second); return sum; } void put(double *array, int size) { double ret = first / second; while (--size >= 0) *array++ = (ret *= second); } friend ostream& operator <<(ostream& out, progression& obj) { return out << "<" << obj.first << "|" << obj.second << ">"; } }; int main(int argc, char* argv[]) { unsigned n = argc > 1 ? atoi(argv[1]) : 7; double *test = new double[n]; progression prg(1, 2); setlocale(LC_ALL, "rus"); while (true) { int i = 0; for (unsigned i = 0; i < n; i++) test[i] = prg[i]; for (unsigned i = 0; i < n; i++) cout << test[i] << " | "; cout << endl; cout << "сколько членов суммировать?: "; cin >> i; cout << prg << " : сумма " << i << " членов = " << prg.summa(i) << endl; double first, divisor; cout << "новые параметры прогрессии " << "(начало знаменатель): "; cin >> first >> divisor; if (0 == first || 0 == divisor) break; prg = progression(first, divisor); } delete[] test; } |
Можна було б, звичайно, як класу геометричній прогресії зберігати необхідну кількість початкових членів ряду. Але це а). вкрай марнотратно і б). при такому поданні незрозуміло, яке число членів ряду зберігати? Показане ж рішення компактне і ефективне:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $ ./progression 1 | 0.5 | 0.25 | 0.125 | 0.0625 | 0.03125 | 0.015625 | сколько членов суммировать?: 10 <1|0.5> : сумма 10 членов = 1.99805 новые параметры прогрессии (начало знаменатель): 1 .3 1 | 0.3 | 0.09 | 0.027 | 0.0081 | 0.00243 | 0.000729 | сколько членов суммировать?: 5 <1|0.3> : сумма 5 членов = 1.4251 новые параметры прогрессии (начало знаменатель): 1 1.1 1 | 1.1 | 1.21 | 1.331 | 1.4641 | 1.61051 | 1.77156 | сколько членов суммировать?: 20 <1|1.1> : сумма 20 членов = 57.275 новые параметры прогрессии (начало знаменатель): 1 -.5 1 | -0.5 | 0.25 | -0.125 | 0.0625 | -0.03125 | 0.015625 | сколько членов суммировать?: 20 <1|-0.5> : сумма 20 членов = 0.666666 новые параметры прогрессии (начало знаменатель): 1 -1.2 1 | -1.2 | 1.44 | -1.728 | 2.0736 | -2.48832 | 2.98598 | сколько членов суммировать?: 15 <1|-1.2> : сумма 15 членов = 7.45774 новые параметры прогрессии (начало знаменатель): 1 -1.2 1 | -1.2 | 1.44 | -1.728 | 2.0736 | -2.48832 | 2.98598 | сколько членов суммировать?: 16 <1|-1.2> : сумма 16 членов = -7.94928 новые параметры прогрессии (начало знаменатель): ^C |
Особливістю рішення є те, що при виконанні операції індексації (вилучення члена прогресії) робиться швидке рекурсивне (алгоритм Хоара) піднесення до степеня знаменника.
Параметром командного рядка можна перевизначити довжину тестового масиву, куди переписуються члени прогресії:
1 2 3 4 5 | $ ./progression 12 1 | 0.5 | 0.25 | 0.125 | 0.0625 | 0.03125 | 0.015625 | 0.0078125 | 0.00390625 | 0.00195312 | 0.000976562 | 0.000488281 | сколько членов суммировать?: 12 <1|0.5> : сумма 12 членов = 1.99951 ... |
йди ти нахуй зі своєю геометричною прогресією