silnia w C

Awatar użytkownika
exculibrus
Użytkownik
Użytkownik
Posty: 77
Rejestracja: 31 sty 2008, o 14:37
Płeć: Mężczyzna
Lokalizacja: Lubin
Podziękował: 28 razy
Pomógł: 6 razy

silnia w C

Post autor: exculibrus »

Mam za zadanie stworzyć program liczący silnie np. ze 100. Jednak nie mam pojęcia dlaczego wyskakuje mi błąd obliczeń. Siedze nad tym od 21 smilies/wink.gif. Wszystkie inne błędy wyeliminowałem. Mój kod:

Kod: Zaznacz cały


// program mnozacy dwie duze liczby i zwracajacy wartosc silni z pobranej liczby
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define SIZE 1000		//rozmiar tablic, wystarczajacy na potrzeby tworcy
short pobierz(short int [], int);		//pobiera liczbe w postaci tablicy cyfr i zwraca ilosc pobranych cyfr
void zeruj(short int [], int);		//zeruje kolejne elementy tablicy
void mnoz(short int [], short int [], short int [], int, short int, short int);		//mnozy dwie liczby w postaci tablicy cyfr
void liczsilnie(short int [], short int, int);	//liczy silnie wskazanej liczby, pobiera tablice, w ktorej zapisuje wynik i jej rozmiar

int main(void)
{
 	short int liczbap[SIZE], liczbad[SIZE], wynik[SIZE];	//liczbap- pierwsza liczba, liczbad- druga liczba
 	short int flaga, IloscZP, IloscZD;		//ZP- Znakow Pierwszej liczby, ZD- Znakow Drugiej liczby
 	short int n;	//zmienna pomocnicza
 	short int silnia; 	//liczba, ktorej silnia bedzie liczona
 	char wybor; 	//zmienna okreslajaca wybor dzialan uzytkownika
 	
 	printf("Jesli chcesz mnozyc liczby wpisz \"M\".\nJesli chcesz liczyc silnie wpisz \"S\".\nAby zakonczyc wpisz \"Z\"\n");
 	wybor = getchar();
	getchar();		
 	if (wybor == 'M' || wybor == 'm')	//liczenie iloczynu
 	{
 	   zeruj(liczbap, SIZE);
 	   zeruj(liczbad, SIZE);
 	   zeruj(wynik, SIZE);
 	   printf("Podaj pierwsza liczbe:\n");
 	   IloscZP = pobierz(liczbap, SIZE);
 	   printf("Podaj druga liczbe:\n");
 	   IloscZD = pobierz(liczbad, SIZE);	
 	   mnoz(liczbap, liczbad, wynik, SIZE, IloscZP, IloscZD);
 	   printf("Wynik to:\n");
 	   for (n = 0; n < SIZE; n++)	//petla wypisujaca wynik mnozenia dwoch liczb w postaci tablic cyfr
 	 	   printf("%1hd", *(wynik + n));
    }
    else if (wybor == 'S' || wybor == 's')		//liczenie silni
    {
	 	 printf("Podaj liczbe, ktorej silnie chcesz obliczyc\n");
	 	 scanf("%hd", &silnia);
	 	 zeruj(wynik, SIZE);
	 	 liczsilnie(wynik, silnia, SIZE);
	 	 for (n = 0; n < SIZE; n++)
	 	 	 printf("%1hd", *(wynik + n));
	}
	else if (wybor == 'Z' || wybor == 'z')		//konczenie programu
		 return 0;
	else					//blad polecenia
		printf("nie ma takiego polecenia. Program zostanie zamkniety\n");
	putchar('\n');    
 	
 	system("PAUSE");
 	return 0;
}

void zeruj(short int tab[], int rozmiar)
{
 	 short int licznik;			//zmienna pomocnicza
 	 
 	 for (licznik = 0; licznik < rozmiar; licznik++)
 	 	 *(tab + licznik) = 0;
}
 	 	 
short pobierz(short int tab[], int rozmiar)
{
 	 short int flaga, n;			//zmienne pomocnicze
 	 short int robocza[rozmiar];		//tablica robocza, wykorzystana do pracy na tablicy glownej
 	 char znak;					//aktualnie pobierany, z wejscia, znak
 	 
 	 zeruj(robocza, rozmiar);
 	 for (n = 0; isdigit(znak = getchar()); n++)		//pobiera kolejne cyfry do tablic docelwej i roboczej
 	 	 *(robocza + n) = *(tab + n) = (short) znak - (short) '0';
 	 zeruj(tab, rozmiar);		//zeruje tablice glowna
 	 for (flaga = 0; flaga <= n; flaga++)		//zmienia kolejnosc wystepowania cyfr w tablicy glownej- 
 	 	 *(tab + (rozmiar - n + flaga)) = *(robocza + flaga);		//- ostatnia cyfra jest na ostatnim miejscu w tablicy
 	 	 
 	 return n;
}

void mnoz(short int pierwsza[], short int druga[], short int iloczyn[], int rozmiar, short IloscZP, short IloscZD)
{
 	 short int n, i, k, flaga, wynik, przepelnienie;
 	 short int robocza[rozmiar];
 	 
 	 zeruj(iloczyn, rozmiar);
 	 for (i = rozmiar - 1, k = 0; i  >= rozmiar - IloscZD; i--, k++)	//oblicza iloczyn
 	 {
 	  	 zeruj(robocza, rozmiar);
 	 	 for (n = rozmiar - 1, przepelnienie = 0; n >= 0; n--)		//mnozy i-ty element pierwszej tablicy przez -
 	 	 {															//n-ty element drugiej tablicy, wyniki zapisuje - 
	  	  	 wynik = *(pierwsza + i) * *(druga + n) + przepelnienie;		//w odpowiednich elementach tablicy roboczej
	  	 	 *(robocza + (n - k)) = wynik % 10;		//odejmowanie zmiennej k, odpowiada przesunieciu wyniku o k miejsc w lewo
	  	 	 przepelnienie = wynik / 10;
		 }
		 if (przepelnienie != 0)		//sprawdza czy nienastapilo przepelnienie
		 {
   		  	printf("Nastapil blad spowodowany zbyt duzym rozmiarem liczby. Program nie dziala prawidlowo\n");
   		  	break;
         }
		 for (n = rozmiar - 1, przepelnienie = 0; n >= 0; n--)  //sumuje odpowiednie elementy tablic roboczych do -
		 {															//odpowiadajacych im elementow tablicy iloczynu
		  	 *(iloczyn + n) = ( *(iloczyn + n) + *(robocza + n) + przepelnienie) % 10;
		  	 przepelnienie = ( *(iloczyn + n) + *(robocza + n) ) / 10;
		 }
		 if (przepelnienie != 0)  //sprawdza czy nienastapilo przepelnienie
		 {
   		  	printf("Nastapil blad spowodowany zbyt duzym rozmiarem liczby. Program nie dziala prawidlowo\n");
   		  	break;
         }
     }
}

void liczsilnie(short int wynik[], short int silnia, int rozmiar)
{	
 	 short int k, n,a, flaga; 		//zmienna pomocnicza
 	 short int ilosc; 		//ilosc cyfr pobranej liczby
 	 short int TabP[rozmiar], TabD[rozmiar];	//tablice pomocnicze
 	 
 	 zeruj(TabP, rozmiar);
 	 zeruj(TabD, rozmiar);
 	 for (ilosc = 1, k = 10; k <= silnia; ilosc++)		//liczy ilosc cyfr pobranej liczby
 	 	 k *= 10;
 	 for (k = silnia, n = rozmiar - 1; n >= 0; n--)		//przypisuje pobrana liczbe tablicy
 	 {
 	  	 *(TabP + n) = k % 10;
 	 	 k /= 10;
     }
     silnia--;			//obniza wartosc liczby o 1 aby w nastepnej petli nie mnozyc dwoch tych samych liczb
 	 for (1 ; silnia > 0; silnia--)		//liczy silnie korzystajac z wczesniejszej petli
 	 {
	  	 for (k = silnia, n = rozmiar - 1; n >= 0; n--)	//przypisuje aktualna liczbe tablicy
 	 	 {
	  	  	 *(TabD + n) = k % 10;
 	 	 	 k /= 10;
  		 }
  		 mnoz(TabP, TabD, wynik, rozmiar, rozmiar, rozmiar);	//mnozy aktualna liczbe przez wynik wczesniejszych iloczynow
  		 for (flaga = rozmiar - 1; flaga >= 0; flaga--)		// wynik aktualnego iloczynu
  		 	 *(TabP + flaga) = *(wynik + flaga);
     }
}


soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

silnia w C

Post autor: soku11 »

Za dużo kodu, za mało objaśnień. Chociażby nawet o tym, co ten program dokładnie robi. Co do problemu, to użyj debuggera i podglądaj wartości.

Pozdrawiam.
miodzio1988

silnia w C

Post autor: miodzio1988 »

Silnia w C i tyle kodu? A nie lepiej skorzystac z prostej rekurencji i juz?
Awatar użytkownika
czeslaw
Użytkownik
Użytkownik
Posty: 2156
Rejestracja: 5 paź 2008, o 22:12
Płeć: Mężczyzna
Lokalizacja: Politechnika Wrocławska
Podziękował: 44 razy
Pomógł: 317 razy

silnia w C

Post autor: czeslaw »

Nawet nie rekurencji... Pseudokod:

Kod: Zaznacz cały

int silnia(int n) {
int iloczyn = 1;
for (int i=2; i<=n; i++) iloczyn *= i;
return iloczyn;
}
Tylko, od razu mówię: do obliczenia \(\displaystyle{ 100!}\) nie wystarczy pamięci.
spajder
Użytkownik
Użytkownik
Posty: 735
Rejestracja: 7 lis 2005, o 23:56
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 2 razy
Pomógł: 133 razy

silnia w C

Post autor: spajder »

Co więcej: do obliczenia \(\displaystyle{ 100!}\) nie wystarczy liczba 3-cyfrowa, możesz przekraczać zakres tablic.
BTW. lepiej zamiast short użyj char, na dzisiejszych komputerach short ma 2 bajty, char 1.
turb0
Użytkownik
Użytkownik
Posty: 2
Rejestracja: 27 mar 2008, o 21:04
Płeć: Mężczyzna
Lokalizacja: Bydgoszcz
Pomógł: 1 raz

silnia w C

Post autor: turb0 »

Witam!

Poprawiony kod znajdziesz na

Kod: Zaznacz cały

http://wklej.org/hash/ef36e2c801/
- już liczy poprawnie 100! - nie wiem czy dokładnie o taki format wyjścia chodziło i czy nie ma więcej błędów.

100! spokojnie się mieści w pamięci natomiast nie mieści się w standardowych typach całkowitych.

Pozdrawiam,
Maciek
Awatar użytkownika
czeslaw
Użytkownik
Użytkownik
Posty: 2156
Rejestracja: 5 paź 2008, o 22:12
Płeć: Mężczyzna
Lokalizacja: Politechnika Wrocławska
Podziękował: 44 razy
Pomógł: 317 razy

silnia w C

Post autor: czeslaw »

Tak, w pamięci standardowych typów całkowitych, to mialem oczywiście na myśli.
ODPOWIEDZ