algorytm sortujący, liczenie statystyk, prosba o sprawdzenie

0

Witam,
Mam problem ze znalezieniem błędu w takim programie, wydaje się on banalnie prosty, ale chyba dla jakiegoś przypadku robi błąd, tylko nie potrafię go znaleźć. Mamy coś takiego jak automatyczną sprawdzarkę, która testuje program na kilku rożnych zestawach danych. Mój program ma status "Błędna odpowiedź".

Oto co program ma robić:
Na standardowym wejściu w pierwszej linii program otrzymuje liczbę N (2 ≤ N ≤ 29 999), która określa liczbę osób, których wiek będzie brany do obliczeń. W następnych N liniach wypisane są (każda w osobnej linii) całkowite długości Di (1 ≤ Di ≤ 1 000 000) życia tych osób.

Wyjście ma się składać z jedenastu linii.
W pierwszej ma być wyświetlony najmniejszy element spośród wczytanych danych.
W drugiej - dokładna wartość pierwszego kwartyla ćwiartkowego (jedno miejsce po przecinku).
W trzeciej - dokładna wartość mediany (jedno miejsce po przecinku).
W czwartej - dokładna wartość trzeciego kwartyla ćwiartkowego (jedno miejsce po przecinku).
W piątej - największy element spośród wczytanych.
W szóstej - średnia zaokrąglona do dwóch miejsc po przecinku.
W siódmej - wartość odchylenia ćwiartkowego zaokrąglona do dwóch miejsc po przecinku.
W ósmej - wartość ćwiartkowego współczynnika zmienności zaokrąglona do dwóch miejsc po przecinku z dopisanym symbolem "%".
W dziewiątej - wartość wskaźnika asymetrii zaokrąglona do dwóch miejsc po przecinku.
W przedostatniej - wartość różnicy pomiędzy średnią wszystkich elementów a średnią elementów pomiędzy kwartylami zaokrągloną do dwóch miejsc po przecinku.
A w ostatniej - wartość współczynnika skośności (o ile istnieje) lub słowo "brak".

dodatkowe info:
średnią arytmetyczną i medianę (czyli wartość środkową w niemalejącym ciągu danych);
pierwszy i trzeci kwartyl (czyli wartości ćwiartkowe - analogiczne do mediany, tylko znajdujące się odpowiednio w 1/4 i 3/4 niemalejącego ciągu danych);
odchylenie ćwiartkowe (będące połową różnicy trzeciego i pierwszego kwartyla);
ćwiartkowy współczynnik zmienności (który jest ilorazem odchylenia ćwiartkowego przez średnią arytmetyczną wyrażonym w procentach);
wskaźnik asymetrii (różnica średniej i mediany)
współczynnik skośności (czyli iloraz, w którym dzielną jest suma kwartyli ćwiartkowych pomniejszona o podwojoną medianę, zaś dzielnikiem podwojone odchylenie ćwiartkowe);
różnicę między średnią arytmetyczną wszystkich wartości a średnią arytmetyczną wartości pomiędzy kwartylami z kwartylami włącznie (w przypadku gdy kwartyle stanowią średnie arytmetyczne dwóch wartości - należy wliczyć do średniej wszystkie wartości brane do wyznaczenia kwartyli);

Mój kod:

#include<stdio.h>
#include<stdlib.h>

int main(){
	int n, i, j, podziel, ikw1, ikw3;// ikw1 ikw3 beda zawierały indeks elementu ciągu najbardziej wewnętrznego branego do obliczania kwartyla
	float kw1, kw3, med, suma=0, suma2=0, temp /**tabA*/;
	
	scanf("%d", &n);
	float tabA[n];
    for(i=0; i<n; i++)
        scanf("%f", &tabA[i]);
    
    for(i=n-1; i>0; i--)//sortowanie elementow tablicy w porzadku niemalejacym
		for(j=0; j<i; j++)
			if(tabA[j]>tabA[j+1]){
				temp = tabA[j];
				tabA[j] = tabA[j+1];
				tabA[j+1] = temp;
			}	
	for(j=0; (n+j)%4; j++);//sprawdzanie podzielności przez 4 dla ilości liczb ciągu
	
	//-1---najmniejszy wyraz
	printf("%.0f\n", tabA[0]);	
	
	//-2---pierwszy kwartyl
    if((j==1)||(j==2))
    	kw1 = tabA[ikw1=((n+j)/4)-1];
	else{
		if(j==0)
			kw1 = (tabA[(n/4)-1]+tabA[ikw1=((n+4)/4)-1])/2;
		if(j==3)
			kw1 = (tabA[((n-1)/4)-1]+tabA[ikw1=((n+3)/4)-1])/2;
	}    
    printf("%.1f\n", kw1);    
    
    //-3---mediana
    if(!(n%2))
		med = (tabA[n/2] + tabA[(n/2)-1])/2;
	else
		med = tabA[(n/2)-1];
		
    printf("%.1f\n", med);    
    
    //-4---trzeci kwartyl
    if((j==1)||(j==2))
    	kw3 = tabA[ikw3=(((3*n)+j)/4)-1];
	else{
		if(j==0)
			kw3 = (tabA[ikw3=((3*n)/4)-1]+tabA[(((3*n)+4)/4)-1])/2;
		if(j==3)
			kw3 = (tabA[ikw3=(((3*n)+1)/4)-1]+tabA[(((3*n)+5)/4)-1])/2;
	} 
    printf("%.1f\n", kw3);    
    
    //-5---najwiekszy wyraz
    printf("%.0f \n", tabA[n-1]);    
    
    //-6---srednia artmetyczna
    for(i=0; i<n; i++)
		suma += tabA[i];
	printf("%.2f \n", suma=suma/n);
	
	//-7---odchylenie cwiartkowe
	printf("%.2f \n", (kw3-kw1)/2);
	
	//-8---cwiartkowy wsp. zmiennosci
	printf("%.2f%c", ((kw3-kw1)/2)/suma*100, 37);
	
	//-9---wskaznik asymetrii
	printf("%.2f \n", suma-med);
	
	//-10---nie wiem jak to nazwac
	for(i = ikw1+1, j=0; i<ikw3; i++, j++)
		suma2 += tabA[i];
	printf("%.2f \n", suma-((suma2+kw1+kw3)/(j+2)));
	
	//-11---wsp. skosnosci
	if(kw3 == kw1)
		printf("brak\n");
	else
		printf("%.2f\n", (kw3+kw1-med-med)/(kw3-kw1));
	
	//free(tabA);
	return 0;
}
 

Nie wiem czy błąd jest po stronie matematycznej, chociaż tutaj wydaje mi się, że nie może być źle, może coś jeśli chodzi o mieszanie float z int, albo gdzieś brakuje miejsca w tablicy przy skrajnych wartościach, nie mam pojęcia co może być tutaj źle. Próbowałem już dynamicznie alokować tablicę ale bez skutku.

0

nie analizowałem kodu tylko przejrzałem. moje uwagi:

  • niektóre sprawdzarki są czułe na dodatkowe białe znaki, a u Ciebie widać
printf("%.0f \n", tabA[n-1]); // spacja po liczbie   
  • suma=suma/n <-- nie wiem czy to zamierzone czy nie, ale ja bym nie ryzykowal takimi zapisami bo latwo zapomniec co jest w zmiennej suma
  • to: printf("%.2f%c", ((kw3-kw1)/2)/suma100, 37); można zapisać tak: printf("%.2f%%", ((kw3-kw1)/2)/suma100);
  • za ten zapis:
        scanf("%d", &n);
        float tabA[n];

wstawiłbym bym Ci 2 gdybym był Twoim nauczycielem, bez względu na to czy ten kod działa prawidłowo czy nie, zamień na:

        float* tabA; // <-- na początku maina jeśli to jest C
        scanf("%d", &n);
        tabA = malloc(sizeof(float)*n); // w c++ tak samo lub tak: tabA = new float[n];
//...
free(tabA); // w 2giej wersji c++: delete [] tabA;

jak dalej Ci nie będzie działać to proponuje zrobić na każdy podpunkt jedną zmienną (o nazwie mowiacej co przechowuje) i wszystkie wzory zgrupować koło siebie i wyswietlanie takze kolo siebie: taki kod duzo latwiej sie analizuje.

0

zastosowałem się do uwag, dzięki. Wrzuciłem teraz taki kod

 
#include<stdio.h>
#include<stdlib.h>

int main(){
	int n, i, j, podziel, ikw1, ikw3;
	float kw1, kw3, med, suma=0, suma2=0, temp, *tabA;
	
	scanf("%d", &n);
	tabA = malloc(sizeof(float)*n);
    for(i=0; i<n; i++)
        scanf("%f", &tabA[i]);
    
    for(i=n-1; i>0; i--)//sortowanie elementow tablicy w porzadku niemalejacym
		for(j=0; j<i; j++)
			if(tabA[j]>tabA[j+1]){
				temp = tabA[j];
				tabA[j] = tabA[j+1];
				tabA[j+1] = temp;
			}	
	for(j=0; (n+j)%4; j++);//sprawdzanie podzielności przez 4 dla ilości liczb ciągu
	
	//-1---najmniejszy wyraz
	printf("%.0f\n", tabA[0]);	
	
	//-2---pierwszy kwartyl
    if((j==1)||(j==2))
    	kw1 = tabA[ikw1=((n+j)/4)-1];
	else{
		if(j==0)
			kw1 = (tabA[(n/4)-1]+tabA[ikw1=((n+4)/4)-1])/2;
		if(j==3)
			kw1 = (tabA[((n-1)/4)-1]+tabA[ikw1=((n+3)/4)-1])/2;
	}    
    printf("%.1f\n", kw1);    
    
    //-3---mediana
    if(!(n%2))
		med = (tabA[n/2] + tabA[(n/2)-1])/2;
	else
		med = tabA[(n/2)-1];
		
    printf("%.1f\n", med);    
    
    //-4---trzeci kwartyl
    if((j==1)||(j==2))
    	kw3 = tabA[ikw3=(((3*n)+j)/4)-1];
	else{
		if(j==0)
			kw3 = (tabA[ikw3=((3*n)/4)-1]+tabA[(((3*n)+4)/4)-1])/2;
		if(j==3)
			kw3 = (tabA[ikw3=(((3*n)+1)/4)-1]+tabA[(((3*n)+5)/4)-1])/2;
	} 
    printf("%.1f\n", kw3);    
    
    //-5---najwiekszy wyraz
    printf("%.0f\n", tabA[n-1]);    
    
    //-6---srednia artmetyczna
    for(i=0; i<n; i++)
		suma += tabA[i];
	printf("%.2f\n", suma=suma/n);
	
	//-7---odchylenie cwiartkowe
	printf("%.2f\n", (kw3-kw1)/2);
	
	//-8---cwiartkowy wsp. zmiennosci
	printf("%.2f%%\n", ((kw3-kw1)/2)/suma*100);
	
	//-9---wskaznik asymetrii
	printf("%.2f\n", suma-med);
	
	//-10---nie wiem jak to nazwac
	for(i = ikw1+1, j=0; i<ikw3; i++, j++)
		suma2 += tabA[i];
	printf("%.2f\n", suma-((suma2+kw1+kw3)/(j+2)));
	
	//-11---wsp. skosnosci
	if(kw3 == kw1)
		printf("brak\n");
	else
		printf("%.2f\n", (kw3+kw1-med-med)/(kw3-kw1));
	
	free(tabA);
	return 0;
}

Mam nadzieję, że będzie dobrze, chociaż wątpię. Sprawdzarka miała być z założenia nieczuła na białe znaki, a co do takiego dziwnego alokowania tablicy to doradził mi kolega dziś na wykładzie, bo wcześniej miałem dobrze, co jeszcze widać w za komentowanych liniach.

0

to znowu ja, nie potrafię poradzić sobie z problemem. Fakt wtedy było sporo błędów. Taki poważnych to chyba 3 czy 4, teraz poprawiłem ale nadal nie jest idealnie. Może ktoś podpowie:

#include <stdio.h>
#include <stdlib.h>

int main(){
	int *tab, n, i, j, temp, ikw1, ikw3, suma=0, suma2=0;
	float kw1, kw3, mediana, arytmetyczna, odchylenieCwiartkowe, cwWspZmiennosci, wskAsymetrii, roz, arytmetyczna2, wspSkosnosci;
	
	scanf("%d", &n);
	tab = malloc(n*sizeof(int));
	for(i=0; i<n; i++){
		scanf("%d", &tab[i]);
	}
	
	for(i=n-1; i>0; i--){//sortowanie elementow tablicy w porzadku niemalejacym
		for(j=0; j<i; j++){
			if(tab[j]>tab[j+1]){
				temp = tab[j];
				tab[j] = tab[j+1];
				tab[j+1] = temp;
			}
		}
	}
	
	for(j=0; (n+j)%4 != 0; j++);//sprawdzenie podzielności ilości elementów ciągu dla 4
	//kwartyle
	if((j == 1)||(j == 2)){
		ikw1 = ((n+j)/4)-1;
		kw1 = (float)tab[ikw1];
		
		ikw3 = (((3*n)+4-j)/4)-1;
		kw3 = (float)tab[ikw3];
	}
	else{
		if(j == 0){
			ikw1 = (n/4)-1;
			kw1 = (float)(tab[ikw1] + tab[((n+4)/4)-1])/2;
			
			ikw3 = (((3*n)+4)/4)-1;
			kw3 = (float)(tab[((3*n)/4)-1]+tab[ikw3])/2;
		}
		if(j == 3){
			ikw1 = ((n-1)/4)-1;
			kw1 = (float)(tab[ikw1]+tab[((n+3)/4)-1])/2;
			
			ikw3 = (((3*n)+5)/4)-1;
			kw3 = (float)(tab[(((3*n)+1)/4)-1]+tab[ikw3])/2;
		}
	}
	//mediana
	if(n%2 == 0){
		mediana = (float)(tab[(n/2)-1]+tab[((n+2)/2)-1])/2;
	}
	else{
		mediana = (float)tab[((n+1)/2)-1];
	}
	
	//arytmetyczna
	for(i=0; i<n; i++){
		suma += tab[i];
		//printf("---%d", suma);
	}
	
	arytmetyczna = (float)suma/n;
	
	//odchylenie cwiartkowe
	odchylenieCwiartkowe = (float)(kw3-kw1)/2;
	
	//cwiartkowy wspolczynnik zmiennosci
	cwWspZmiennosci = (odchylenieCwiartkowe/arytmetyczna)*100;
	
	//wskaznik asymetrii
	wskAsymetrii = arytmetyczna-mediana;
	
	//roz
	//printf("---%d\n", ikw1);
	for(i=0; ikw1<=ikw3; ikw1++, i++){
		suma2 += tab[ikw1];
	}
	arytmetyczna2 = (float)suma2/i;
	roz = (float)arytmetyczna - arytmetyczna2;
	
	//wspolczynnik skosnosci
	if(kw1-kw3 !=0){
		wspSkosnosci = (float)(kw1+kw3-mediana-mediana)/(2*odchylenieCwiartkowe);
	}
	
	//-1---najmniejszy wyraz
	printf("%d\n", tab[0]);	
	
	//-2---pierwszy kwartyl
    printf("%.1f\n", kw1);    
    
    //-3---mediana
    printf("%.1f\n", mediana);    
    
    //-4---trzeci kwartyl
    printf("%.1f\n", kw3);    
    
    //-5---najwiekszy wyraz
    printf("%d\n", tab[n-1]);    
    
    //-6---srednia artmetyczna
	printf("%.2f\n", arytmetyczna);
	
	//-7---odchylenie cwiartkowe
	printf("%.2f\n", odchylenieCwiartkowe);
	
	//-8---cwiartkowy wsp. zmiennosci
	printf("%.2f%%\n", cwWspZmiennosci);
	
	//-9---wskaznik asymetrii
	printf("%.2f\n", wskAsymetrii);
	
	//-10---nie wiem jak to nazwac
	printf("%.2f\n", roz);
	
	//-11---wsp. skosnosci
	if(kw3 == kw1)
		printf("brak\n");
	else
		printf("%.2f\n", wspSkosnosci);
	
	free(tab);
	return 0;
}

 
0

Spróbuj zmienić float na double, może być problem z dokładnością. Wartości musisz podawać z dokładnością nawet do 6 cyfr znaczących, po 30000 obliczeń float się do tego nie nadaje. Ogólnie stosowanie floata ma sens w przypadku ograniczeń pamięciowych, lub potrzeby szybkich obliczeń przeprowadzanych na tablicy (simd), gdy wysoka dokładność nie ma dużego znaczenia (np. symulacje naukowe).

0

nie wydaje mi się, żeby to mogło być powodem błędu. Najbardziej skomplikowana operacja tutaj to jest policzenie dwóch średnich arytmetycznych z liczb całkowitych i ich dodanie, a wynik i tak ma być zaokrąglony do dwóch miejsc po przecinku. Mam też plik wykonywalny od kolegi który zaliczył to zadanie i na jakieś 70 przypadków, które sprawdziłem wyniki są identyczne, a starałem się wymyślać zupełnie różne testy. Niepokoi mnie trochę zachowanie funkcji printf mianowicie, jak kompiluje pod Windows w Dev-C++ który używa gcc to zaokrąglenia są prawidłowe napotkałem tylko taki przypadek, że dla samych piątek np 5.555 zaokrągli do 5.55 a nie 5.56. Zaś np 5.625, już prawidłowo do 5.63. Jednak na serwerze z zainstalowanym FreeBSD gdzie działa sprawdzarka zawsze ostatnią piątkę zaokrągla w dół. Rozmawiałem z prowadzącymi zajęcia i powiedziano mi, że faktycznie jest rozbieżność, ale że testy były też generowane tą funkcją więc powinno się zgadzać.

0

Jak wartości są zbliżone do maksimum (10^6) to okazuje się, że potrzebujesz już 7 cyfr znaczących, co jest na granicy dokładności floata. Po prostu sprawdź, czy nie jest to błędem.
Edit po wygenerowaniu 30000 losowych liczb od 700000 do 1000000 otrzymałem dla floata:

700000
776940.0
852920.0
926010.0
999980
-7368.42
74535.00
-1011.55%
-860288.44
-936.38
-0.02
 

a dla double'a:

700000
776940.0
852920.0
926010.0
999980
-7368.42
74535.00
-1011.55%
-860288.42
-936.38
-0.02
 
0

dzięki, właśnie to było błędem;) teraz jest ok. Jeszcze raz dzięki

1 użytkowników online, w tym zalogowanych: 0, gości: 1