Це завдання має дуже велике практичне застосування: в статистичній обробці даних, обробці часових рядів, в цифровій обробці сигналів стосовно до цифрових відліках сигналу. Постановка завдання така:
– вводиться послідовність (речових) чисел …
– потрібно прорахувати, в підсумку, середнє значення і дисперсію (або ЮКО: середньоквадратичне відхилення) числового ряду.
Нагадування для тих, хто не дружить з математикою:
– для послідовності N чисел a1, a2, … aN
– середнє значення обчислюємо як M = 1 / N * SUM( я = 1, N, до )
– дисперсію обчислюємо як D = 1 / N * SUM( я = 1, N, ( до – M ) ** 2 )
– СКО обчислюємо як S = SQRT( D )
Фішка тут в тому, що для обчислення дисперсії перш потрібно обчислити середнє значення M. Але таке пряме обчислення зажадає 2-х проходів по послідовності: спочатку для обчислення M, а потім знову для обчислення D. Це недозволена розкіш, якщо потрібно робити обчислення для ряду в 10 000, 100 000 или 1 000 000 значений. Обчислення потрібно зробити в один прохід, без зберігання всієї послідовності: після введення чергового числа всі попередні губляться…
Подсказка: перш програмування спробуйте перетворити вираз для D так, щоб входить значення M винести з-під операції підсумовування.
Рішення:
перш, ніж писати код, займемося перетворенням формули для обчислення дисперсії (розкриємо квадрат різниці під сумою):
D = 1 / N * SUM( я = 1, N, ( до – M ) ** 2 ) =
= 1 / N * SUM( я = 1, N, до ** 2 ) – 2 * 1 / N * SUM( я = 1, N, до ** 2 ) * M + 1 / N * N * M ** 2 =
= 1 / N * SUM( я = 1, N, до ** 2 ) – 2 * M ** 2 + M ** 2 =
= 1 / N * SUM( я = 1, N, до ** 2 ) – M ** 2
або, якщо висловити це словами: усереднена (поділена на N) сума квадратів чисел, мінус квадрат їх середнього. Тепер ми можемо по ходу надходження чисел ряду накопичувати їх суму (s1 – для подальшого обчислення середнього) і суму квадратів (s2 – для подальшого обчислення дисперсії), а обчислення підсумкових характеристик відкласти до завершення надходження числового ряду.
А тепер спокійно пишемо який реалізує це код:
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 | #include <iostream> #include <sstream> using namespace std; int main() { setlocale(LC_ALL, "rus"); string e; int n; // счётчик чисел double d, s1, s2; while (true) { s1 = s2 = 0.0; n = 0; cout << "Вводите последовательность чисел: "; getline(cin, e); istringstream ist(e); while (ist >> d) { n++; s1 += d; s2 += d * d; } s1 /= n; s2 = s2 / n - s1 * s1; cout << "Введено чисел " << n << ", среднее = " << s1 << ", дисперсия = " << s2 << endl; } } |
всього то! (код сильно спрощений: весь числовий ряд вводиться в одному рядку, закінчується Enter, не включена обробка помилкового введення та ін.).
А зараз – як це працює: