Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Liczba najbliższa średniej - Mirosław Zelent odcinek 11 zadanie domowe

Ostatnio zmodyfikowano 2016-03-10 17:29
Autor Wiadomość
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.
C/C++
#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 ) ); // "1- ..." jest na pewno poprawnie zastosowane i konieczne? Jeśli tak, to prosiłbym o wytłumaczenie po co ono tutaj jest
        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.
P-145672
Kaikso
» 2016-03-08 23:21:03
Ten kod powinien być bardziej zrozumiały:

C/C++
#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;
}
P-145773
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:
C/C++
for( float & x: liczby )
Czy ten zapis jest równy temu?
C/C++
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ą:
C/C++
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
?
P-145800
carlosmay
» 2016-03-09 18:00:43
for( float & x: liczby )
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.
P-145801
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 :-)
C/C++
#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 :-)
P-145804
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
C/C++
#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;
}
P-145806
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 :-)
P-145807
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.
P-145811
« 1 » 2
  Strona 1 z 2 Następna strona