Lich555 Temat założony przez niniejszego użytkownika |
Liczba najbliższa średniej - Mirosław Zelent odcinek 11 zadanie domowe » 2016-03-07 18:28:43 Witam. Mam problem z zadaniem domowym z 11 odcinka kursu C++ Pana Mirosława Zelenta. Program ma obliczyć średnią z 5 liczb przez nas wprowadzonych i wypisać liczbę najbliższą średniej. Napotkałem takie rozwiązanie, lecz nie do końca je rozumiem. #include <iostream>
using namespace std;
int main() { float liczby[ 5 ], suma = 0, srednia = 0, x[ 5 ], najmniejsza; int indeks; cout << "Podaj 5 liczb: "; for( int i = 0; i < 5; i++ ) { cin >> liczby[ i ]; suma += liczby[ i ]; } srednia = suma / 5; cout << endl << "Srednia wynosi: " << srednia; for( int i = 0; i < 5; i++ ) { x[ i ] =( 1 -( liczby[ i ] / srednia ) ); if( x[ i ] < 0 ) x[ i ] = - x[ i ]; } najmniejsza = x[ 0 ]; indeks = 0; for( int i = 0; i < 5; i++ ) if( x[ i + 1 ] < najmniejsza ) { najmniejsza = x[ i + 1 ]; indeks = i + 1; } cout << endl << "Liczba najblizsza sredniej to: " << liczby[ indeks ]; for( int i = 0; i < 5; i++ ) if( x[ i ] == x[ indeks ] && liczby[ i ] != liczby[ indeks ] ) cout << "," << liczby[ i ]; return 0; }
Wpisałem takie liczby: 1, 2, 9, 5, -6 Wynik: Srednia wynosi: 2.2 Liczba najblizsza sredniej to: nan Wynik jak widać nie jest prawidłowy z niewiadomych mi przyczyn. |
|
Kaikso |
» 2016-03-08 23:21:03 Ten kod powinien być bardziej zrozumiały: #include <iostream>
int main() { float liczby[ 5 ], suma = 0; std::cout << "Podaj 5 liczb" << std::endl; for( float & x: liczby ) { std::cout << ">> "; std::cin >> x; suma += x; } float srednia = suma / 5; std::cout << "Średnia wynosi: " << srednia << std::endl; float najblizsza = liczby[ 0 ]; float roznica = najblizsza - srednia; roznica = roznica >= 0 ? roznica: - roznica; for( size_t i = 1; i < 5; i++ ) { float roznicax = liczby[ i ] - srednia; roznicax = roznicax >= 0 ? roznicax: - roznicax; if( roznicax < roznica ) { najblizsza = liczby[ i ]; roznica = roznicax; } } std::cout << "Najbliższa: " << najblizsza << std::endl; return 0; }
|
|
Lich555 Temat założony przez niniejszego użytkownika |
» 2016-03-09 17:51:12 Mam pytanie do tego programu. Nie wiem co robi ten operator: Czy ten zapis jest równy temu? for( float x = 0; x < 5; x++ )
Z tego co się orientuję, to jest referencja. :P Nie za bardzo zgłębiłem ten temat. Chodzi o to, że tworzymy referencję, której przekazujemy tablicę? Mam również problem z tą linijką: roznica = roznica >= 0 ? roznica: - roznica;
To jest inny zapis "if"? Jeśli tak, to mógłbyś mi przedstawić to właśnie w "if"? Czy size_t nie można zastąpić zwykłym int ? |
|
carlosmay |
» 2016-03-09 18:00:43 Nagłówek pętli zakresowej dostępnej od standardu C++11. roznica = roznica >= 0 ? roznica: - roznica; |
Wyrażenie warunkowe: przypisuje do zmiennej roznica w zależności od spełnienia warunku roznica >= 0, wartość niezmienioną bądź przciwną. W kursie też jest wzmianka na ten temat. Jak znajdę podrzucę link. |
|
mokrowski |
» 2016-03-09 18:16:54 To co podałeś jako kod przykładowy, nie jest poprawnym rozwiązaniem. Mam tylko +podejrzenie_ co chciał uzyskać autor "niewiadomego kodu". Chciał uniknąć problemu utraty dokładności przy dużych wartościach zmiennoprzecinkowych. Zrobił to jednak nieprawidłowo a poniżej umieścił "ręcznie zaimplementowaną" funkcję fabs(). Nie chcę pozbawiać Cię frajdy własnego rozwiązania więc podaję jako inspirację rozwiązanie intensywnie korzystające z biblioteki standardowej oraz C++11. Nie wydzielałem do funkcji bo myślę że kod jest bardzo krótki. Zaznaczam jednocześnie że rozwiązanie wybiega poza etap 11 lekcji Zelenta :-) #include <iostream> #include <vector> #include <algorithm> #include <numeric> #include <cmath>
using namespace std;
int main() { vector < float > values( 5 ); cout << "Podaj 5 liczb oddzielonych spacją lub znakiem nowej linii: " << endl; for( float & val: values ) { cin >> val; } float average = accumulate( values.cbegin(), values.cend(), 0.0 ) / values.size(); float nearest_value = values[ 0 ]; for_each( values.cbegin(), values.cend(),[ & nearest_value, & average ]( float val ) { nearest_value = fabs( average - val ) < fabs( average - nearest_value ) ? val : nearest_value; } ); cout << "Średnia to: " << average << endl; cout << "Pierwsza liczba najbliższa średniej to: " << nearest_value << endl; }
Oczywiście można poczynić optymalizacje. Ten kod operuje na złożoności O(2n). Jeśli liczby były by wyłącznie dodatnie, można kod zoptymalizować do poziomu złożoności O(n). Tu także liczona jest w accumulate(..) suma... no ale chciałem pokazać accumulate(...) a nie sumę liczoną na piechotę bo to pokazał już kolega :-) |
|
michal11 |
» 2016-03-09 19:00:40 Dlaczego vector a nie array skoro de facto masz statyczną tablicę ? Accumulate i zwykły for ma dokładnie taką samą złożoność, żadna różnica. Dlaczego korzystasz z fabs skoro według tego: abs() jest przeciążenie funkcji abs dla argumentów zarówno float jak i double ? Nie mniej podoba mi się twój kod :) Jeszcze może dorzucę swoje rozwiązanie, wzorowałem się na http://stackoverflow.com/a/3628082#include <iostream> #include <algorithm> #include <array> #include <numeric> #include <cmath>
int main() { std::array < int, 10 > v( { 10, 20, 30, 30, 20, 10, 10, 20, 500, 10000 } ); float average = std::accumulate( v.cbegin(), v.cend(), 0.0 ) / v.size(); auto nearest = std::min_element( v.cbegin(), v.cend(),[ & average ]( int left, int right ) { return abs( left - average ) < abs( right - average ); } ); std::cout << "average " << average << '\n'; std::cout << "nearest " << * nearest << '\n'; return 0; }
|
|
mokrowski |
» 2016-03-09 20:35:23 Ogólnie.. zależało mi na "edukacyjnej" wartości kodu... a w szczegółach.. 1. Dlatego że jeśli jest wybór, należy preferować vector ponad tablicę. Tablica to tak naprawdę cienkie opakowanie na wskaźnik a on jest błędogenny tak więc i tablica jest błędogenna. Odsyłam do CERT Secure Coding Stnadards gdzie można znaleźć informacje statystyczne co warto a czego nie stosować https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=637 . Wprawdzie można stosować jeszcze tablicę z <array> która jest lepsza niż "tablica goła" no ale vector jest bardziej uniwersalny :-) Kontener vector poza tym alokuje pamięć na stercie a nie na stosie który jest mały (w porównaniu do sterty). Tablica? Tak. owszem... w kodzie embedded gdzie występuje także "rozpaczliwy void *" wtedy czemu nie.. :-) 2. Jak użyjesz accumulate(...) masz mniejsze prawdopodobieństwo że popełnisz błąd własnej implementacji... accumulate :-) Biblioteka standardowa mało ma błędów a własny kod zawsze gdzieś będzie miał.. 3. Co do fabs(), zdarzyło mi się że nie był przeciążony.. czyli... z przyzwyczajenia (jakiś BSD tego nie miał... o ile pamiętam OpenBSD)... przyzwyczajenia :-)
|
|
michal11 |
» 2016-03-09 21:48:17 Ad. 1 nie chodziło mi o zwykłą tablicę tylko właśnie o array. Czym vector jest bardziej uniwersalny od array w tym przypadku ? Ja pisałem o tym konkretnym przypadku a nie o programowanie w ogóle. |
|
« 1 » 2 |