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

Nieprawidłowo zwracana wartość mediany

Ostatnio zmodyfikowano 2017-03-29 23:31
Autor Wiadomość
e5500
Temat założony przez niniejszego użytkownika
Nieprawidłowo zwracana wartość mediany
» 2017-03-29 00:55:16
Witam. Próbuję napisać funkcję liczącą medianę dla wartości zmiennoprzecinkowych znajdujących się w zbiorze vector<float> tab. Korzystając ze wzorów ogólnych, wziąłem pod uwagę konieczność przesunięcia wszystkich wartości miejsc liczb w vector o -1, co wynika z faktu, że numeracja zaczyna się od 0. Funkcja działa prawidłowo dla ciągu liczb o ich nieparzystej ilości. Niestety, przy podaniu parzystej ilości, funkcja zwraca wartość tab[ ( dlugosc / 2 ) + 1

Przykładowo dla ciągu 1 2 3, wynik 2
Dla 1 2 3 4, wynik 3
Dla 1 2 3 4 5 6, wynik 4

Poniżej zamieszczam mój kod. Z góry dziękuję za cenne rady i wskazówki!

C/C++
float mediana( vector < float > tab )
{
    sortuj( tab );
    float mediana;
    int dlugosc = tab.size() + 1;
   
    if( dlugosc % 2 == 0 )
         mediana =( tab[ dlugosc / 2 - 1 ] + tab[ dlugosc / 2 ] ) / 2;
    else
         mediana = tab[( dlugosc - 1 ) / 2 ];
   
    return mediana;
}
P-159556
mokrowski
» 2017-03-29 02:46:33
Sortowanie całości kontenera aby policzyć medianę jest nieefektywne. Potrzebujesz przecież wiedzieć jaka liczba jest na określonym miejscu jeśli by kontener był posortowany. Tu masz poprawiony swój kod oraz propozycję zrobienia tego efektywniej:
C/C++
#include <vector>
#include <iostream>
#include <algorithm>

float mediana1( std::vector < float >& tab )
{
    std::sort( tab.begin(), tab.end() );
    float mediana;
    int dlugosc = tab.size();
   
    if( dlugosc % 2 == 0 )
         mediana =( tab[ dlugosc / 2 ] + tab[( dlugosc / 2 ) - 1 ] ) / 2;
    else
         mediana = tab[ dlugosc / 2 ];
   
    return mediana;
}

float mediana2( std::vector < float > vec ) {
    std::nth_element( vec.begin(), vec.begin() + vec.size() / 2, vec.end() );
    auto m1 = vec[ vec.size() / 2 ];
    if( vec.size() % 2 ) {
        return m1;
    }
    std::nth_element( vec.begin(), vec.begin() +( vec.size() / 2 ) - 1, vec.end() );
    auto m2 = vec[( vec.size() / 2 ) - 1 ];
    return( m1 + m2 ) / 2;
}

std::ostream & operator <<( std::ostream & os, const std::vector < float >& vec ) {
    for( const auto & v: vec ) {
        os << v << " ";
    }
    return os;
}
int main() {
    std::vector < float > vec = { 1, 2, 3, 4, 5 };
    std::cout << "Medianą wektora " << vec << ", jest: " << mediana1( vec ) << '\n';
}
P-159557
e5500
Temat założony przez niniejszego użytkownika
» 2017-03-29 22:24:16
@mokrowski mógłbyś mi wytłumaczyć jakiego typu wartości użyłeś deklarując m1 jako auto? Mój MinGW niestety nie rozumie tego kodu. Byłbym również wdzięczny za wyjaśnienie mi działania funkcji std::ostream & operator.

Dodatkowo pojawił się kolejny problem. Po zaimplementowaniu poprawionej wersji mojej funkcji, nie mogę wykonać jej na argumentach będącymi liczbami zmiennoprzecinkowymi. Doskonale radzi sobie z liczbami całkowitymi, będąc sama w stanie zwrócić wartość z przecinkiem, niestety z jakiegoś powodu znalezienie się takiej liczby w argumentach zawiesza program. Dodam, że inne funkcje programu radzą sobie dobrze ze wszystkimi wartościami typu float
P-159591
mokrowski
» 2017-03-29 23:31:37
Dodaj do swojego kompilatora przełącznik -std=c++11
To przełącza go w tryb standardu z 2011 roku. Kompilator przy zmiennej auto sam dedukuje jej typ. Jeśli dalej kod nie będzie się budował, uaktualnij swój kompilator bo .. jest antyczny :-/ Mamy przecież 2017.
ostream& operaotor<< przeciąża metodę która umożliwia wydrukowanie na konsolę zawartość kontenera vector, co widzisz w main().
Daj znać czy poprawki zadziałały.

Poniżej umieszczam "zdegradowany" do starych kompilatorów przykład:
C/C++
#include <vector>
#include <iostream>
#include <algorithm>

float mediana1( std::vector < float >& tab )
{
    std::sort( tab.begin(), tab.end() );
    float mediana;
    int dlugosc = tab.size();
   
    if( dlugosc % 2 == 0 )
         mediana =( tab[ dlugosc / 2 ] + tab[( dlugosc / 2 ) - 1 ] ) / 2;
    else
         mediana = tab[ dlugosc / 2 ];
   
    return mediana;
}

float mediana2( std::vector < float > vec ) {
    std::nth_element( vec.begin(), vec.begin() + vec.size() / 2, vec.end() );
    float m1 = vec[ vec.size() / 2 ];
    if( vec.size() % 2 ) {
        return m1;
    }
    std::nth_element( vec.begin(), vec.begin() +( vec.size() / 2 ) - 1, vec.end() );
    float m2 = vec[( vec.size() / 2 ) - 1 ];
    return( m1 + m2 ) / 2;
}

std::ostream & operator <<( std::ostream & os, const std::vector < float >& vec ) {
    for( size_t i = 0; i < vec.size(); ++i ) {
        os << vec[ i ] << " ";
    }
    return os;
}
int main() {
    std::vector < float > vec;
    vec.push_back( 1.0 );
    vec.push_back( 2.0 );
    vec.push_back( 3.0 );
    vec.push_back( 4.0 );
    vec.push_back( 5.0 );
    vec.push_back( 6.0 );
    std::cout << "Medianą wektora " << vec << ", jest: " << mediana1( vec ) << '\n';
}
P-159593
« 1 »
  Strona 1 z 1