C - kalkulator na dużych liczbach, dzia

Potrzebujesz pomocy z C, C++, perl, python, itp.
kristof
Posty: 16
Rejestracja: 10 października 2007, 09:05

C - kalkulator na dużych liczbach, działania pisemne

Post autor: kristof »

Więc tak pisze program razem z kolegą wykonujący pisemnie mnożenie, dodawanie, odejmowanie i dzielenie. Doszliśmy do czegoś co powinno działać, a okazuje się że nie daje rady program aż w jednym miejscu.
Wywala mi bład że

Kod: Zaznacz cały

returnValue = get_value(returnValue, actions[i], input[j]);
nie ma odpowiednich zmiennych, które wykorzystuje ta funkcja do której się to odnosi.

Ja nie wiem gdzie tkwi ten błąd co jest nie tak zadeklarowane-> po części ze względu na uboższą wiedzę odnośnie C niż mój kolega posiada, w sumie on sam nie wie dlaczego to nie działa tak jak powinno.

Nie wiem co to da ale poniżej umieszczam cały kod programu. I z góry bardzo dziękuje za pomoc w tym
A jeśli jest możliwość tego uproszczenia to bardzo ale to bardzo prosiłbym o sugestie -> toż to jest mały sajgon tam ?

Kod: Zaznacz cały

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<ctype.h>

# define MAX 4

// do sprawdzania czy akcja jest ok
int is_valid_action( char action )
{
   if ( action == '+' || action == '-' || action == '*' || action == '/' || action == '=' )
   {
       return 1;
   }

   return 0;
}

// tutaj liczymy całość
// jedziemy po tablicy input i wg odpowiedniego klucza tablicy actions wykonujemy dane matematyczne działanie
int do_calc( int input[], char actions[] )
{
   int i, j, returnValue, firstCall = 0;

   for ( i = 0; i < sizeof(input); i++)
   {
       // potrzebne zeby wziasc I element z tablicy input, potem returnValue przechowuje juz wykonane działania
       // tzn mamy działanie 10+60*2 czyli za pierwszym razem returnValue = 10; przy i=1; returnValue = 60;
       if ( firstCall  == 0 )
       {
               returnValue = input[i];
           firstCall   = 1;
       }

       // tutaj wykonujemy działania, czyli returnValue przechowuje ostatnią wartość działania lub za I przebiegiem For, I element tablicy,
       // actions[i] - jaka akcje wykonać
       // input[j] - nastpna wartość w talibcy input czyli np. to nasze 60 w I przebiegu funkcji FOR ;
       returnValue = get_value(returnValue, actions[i], input[j]);
       j++;
   }

   return returnValue;
}

// tutaj dokładnie wykonujesz działania, chyba nie trzegba szczegoółowo omawiac
int get_value( int current, char action, int nextValue )
{
   switch ( action )
   {
       case '+':
           return current + nextValue;
       break;

       case '-':
           return current - nextValue;
       break;

       case '*':
           return current * nextValue;
       break;

       case '/':
           return current / nextValue;
       break;

       default:
           printf("Error: brak akcji \n");
           return 0;
       break;
   }
}

int main(void)
{
       char
       actions[MAX], action;
       int
       input[MAX], inputIndex = 0, actionIndex, i;

   printf("Welcome to SimpleCalc v 0.1.0.0 \n");
   printf("Podaj pierwszą liczbę \n");
   scanf("%s", &action);

   while( action != '=' )
   {
       printf("Wybierz działanie ( '+', '-', '*', '/' ) \n");
       scanf("%s", &action);

       if (isxdigit(action)) // sprawdzam czy dodać wartość do liczenia
       {
           input[inputIndex] = atoi(action);
           inputIndex++;

           if (inputIndex > (actionIndex + 1) ) // ten potworek jest żeby wsio sie zgadzało miedzy np. input[] i actions[]
           {
               actionIndex = actionIndex + 1;
           }
       }
       else // czy dodać wpisaną komende jako akcje
       {
           if (is_valid_action(action))
           {
               actions[actionIndex] = action;
               actionIndex++;

               if (actionIndex > (inputIndex + 1)) // ten potworek jest żeby wsio sie zgadzało miedzy np. input[] i actions[]
               {
                       inputIndex = inputIndex + 1;
               }
           }
           else
           {
               printf("KERNEL PANIC: \n Niedozwolona akcja! \n");
               return 0;
           }
       }
     
   }


   // sprawdzam czy mam dane, jak nie to koniec prog.
   if (sizeof(input) == 0)
   {
       printf("Error: \n brak danych! \n");
       return 0;
   }

   // wywal na screen wprowadzone dane i jakie operacje pokolei zrobilismy
   for ( i = 0; i < sizeof(input); i++)
   {
       printf("%d \n", input[i]);
       printf("%s \n", actions[i]);
   }

   // podsumowanie + rezultat do_calc czyli końcowe wyliczenia :d
   printf("------------------------ \n\t\t %d", do_calc( input, actions ) );

   // the end :P nice programist story :D
       return 0;
}
Theq
Beginner
Posty: 140
Rejestracja: 16 kwietnia 2007, 19:00
Lokalizacja: Legnica

Post autor: Theq »

Na pierwszy rzut oka brakuje deklaracji funkcji get_value
kristof
Posty: 16
Rejestracja: 10 października 2007, 09:05

Post autor: kristof »

Dobra uwaga - nie zauważyłem tego..
Więc tak program uporządkowałem, wsio niby jest ładnie programik się pięknie kompiluje i nawet uruchamia
jednak po wprowadzeniu pierwszej liczby i znaku wywala mi jakiś błąd i dalej nie działa....

teraz to wygląda tak -> chyba trochę bardziej czytelnie -> tzn. na pewno dla mnie

Kod: Zaznacz cały

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<ctype.h>

# define MAX 4


int is_valid_action( char action );
int get_value( int current, char action, int nextValue );
int do_calc( int input[], char actions[] );

int main(void)
{
       char
       actions[MAX], action;
       int
       input[MAX], inputIndex = 0, actionIndex, i;

   printf("Welcome to SimpleCalc v 0.1.0.0 \n");
   printf("Podaj pierwszą liczbę \n");
   scanf("%s", &action);

   while( action != '=' )
   {
       printf("Wybierz działanie ( '+', '-', '*', '/' ) \n");
       scanf("%s", &action);

       if (isxdigit(action)) // sprawdzam czy dodać wartość do liczenia
       {
           input[inputIndex] = atoi(action);
           inputIndex++;

           if (inputIndex > (actionIndex + 1) ) // ten potworek jest żeby wsio sie zgadzało miedzy np. input[] i actions[]
           {
               actionIndex = actionIndex + 1;
           }
       }
       else // czy dodać wpisaną komende jako akcje
       {
           if (is_valid_action(action))
           {
               actions[actionIndex] = action;
               actionIndex++;

               if (actionIndex > (inputIndex + 1)) // ten potworek jest żeby wsio sie zgadzało miedzy np. input[] i actions[]
               {
                       inputIndex = inputIndex + 1;
               }
           }
           else
           {
               printf("KERNEL PANIC: \n Niedozwolona akcja! \n");
               return 0;
           }
       }
     
   }


   // sprawdzam czy mam dane, jak nie to koniec prog.
   if (sizeof(input) == 0)
   {
       printf("Error: \n brak danych! \n");
       return 0;
   }

   // wywal na screen wprowadzone dane i jakie operacje pokolei zrobilismy
   for ( i = 0; i < sizeof(input); i++)
   {
       printf("%d \n", input[i]);
       printf("%s \n", actions[i]);
   }

   // podsumowanie + rezultat do_calc czyli końcowe wyliczenia :d
   printf("------------------------ \n\t\t %d", do_calc( input, actions ) );

   // the end :P nice programist story :D
       return 0;
}

int is_valid_action( char action )
{
   if ( action == '+' || action == '-' || action == '*' || action == '/' || action == '=' )
   {
       return 1;
   }

   return 0;
}


int do_calc( int input[], char actions[] )
{
   int i, j, returnValue, firstCall = 0;

   for ( i = 0; i < sizeof(input); i++)
   {
       // potrzebne zeby wziasc I element z tablicy input, potem returnValue przechowuje juz wykonane działania
       // tzn mamy działanie 10+60*2 czyli za pierwszym razem returnValue = 10; przy i=1; returnValue = 60;
       if ( firstCall  == 0 )
       {
               returnValue = input[i];
           firstCall   = 1;
       }

       // tutaj wykonujemy działania, czyli returnValue przechowuje ostatnią wartość działania lub za I przebiegiem For, I element tablicy,
       // actions[i] - jaka akcje wykonać
       // input[j] - nastpna wartość w talibcy input czyli np. to nasze 60 w I przebiegu funkcji FOR ;
       returnValue = get_value(returnValue, actions[i], input[j]);
       j++;
   }

   return returnValue;
}

// tutaj dokładnie wykonujesz działania, chyba nie trzegba szczegoółowo omawiac
int get_value( int current, char action, int nextValue )
{
   switch ( action )
   {
       case '+':
           return current + nextValue;
       break;

       case '-':
           return current - nextValue;
       break;

       case '*':
           return current * nextValue;
       break;

       case '/':
           return current / nextValue;
       break;

       default:
           printf("Error: brak akcji \n");
           return 0;
       break;
   }
}
W sumie i tak teraz siedzę nad drugą wersją tego program ale tam już zablokowałem się przy mnożeniu..chce go zrobić tak by laik wiedział jak on działa czyli praca na stringach tylko przy wprowadzaniu danych potem przejście do duuużych tablic int -> np liczbę 12345678903.. zapisuje w postaci tablicy: [1][2][3][4][5][6][7][8][9][0][3][..]
potem wykonywanie reszty zajęć -> chyba to jest prostsza metoda ?

Dzięki za podpowiedź :) i za dalszą pomoc :)

Dodano kilka godzin później:

Zna ktoś jakiś w miarę prosty algorytm na mnożenie w słupku ? zacinam się przy wpisywaniu tych sum -> tzn ciągle coś z tego kasuje -> chyba że rezultat można prosto do stringa wprowadzić, a potem z niego odczytać podane wyniki ?
ponton
Beginner
Posty: 406
Rejestracja: 24 stycznia 2007, 01:40
Lokalizacja: Kalisz/Wroc³aw

Post autor: ponton »

Kod: Zaznacz cały

  scanf("%s", &action); 
Wczytujesz stringa do zmiennej char. Zamień %s na %c. Dwa razy tak robisz.

Drugi warning, jaki mi wyskoczył: passing argument 1 of 'atoi' makes pointer from integer without a cast

Kod: Zaznacz cały

input[inputIndex] = atoi(action);
Skoro action jest charem, czyli jednym znakiem, cyfrą, to zamiana na liczbę jest taka:

Kod: Zaznacz cały

inpute[inputeIndex] = action-'0';
kristof
Posty: 16
Rejestracja: 10 października 2007, 09:05

Post autor: kristof »

heh jestem głupi już, udało mi się to wszystko naprawić ale otrzymałem kalkulator na max 18cyfr;/ co mnie nie satysfakcjonuje..muszę ich mieć ponad 200;/
Wie ktoś może co trza tam poprawić żeby to tak działało jak ma ? bo ja już wysiadłem po spędzeniu nocy nad tym badziewiem;/
Jak to jest z tym żeby ominąć wypisywanie tych liczb do int albo long long i jeszcze do tego wykonać działania na nich? Ja juz w tym badziewiu się gubię :/
Immortal
Posty: 31
Rejestracja: 11 grudnia 2007, 12:15
Lokalizacja: Kraków

Post autor: Immortal »

kristof pisze:Jak to jest z tym żeby ominąć wypisywanie tych liczb do int albo long long i jeszcze do tego wykonać działania na nich?
Po prostu nie zamieniaj tych liczb na inty :) Rob tak jakbyś mnożył/dowawał/dzielił pisemnie. Ja miałem kiedyś takie coś napisać tyle że w c++. masz tutaj moje dowawanie np:

Kod: Zaznacz cały

CLiczby & CLiczby: :o perator+=(const CLiczby &X)
/** Operator +=. Przypisuje liczbie wartosc dodawania druga liczba. */
{
   int len = liczba.length()]-'0') + (int)(X.liczba[0]-'0');

   for (int i=0; i<X.liczba.length()-1; i++)
       {         
	 if (x>9)
	    {
	      liczba[i]=(x-10)+'0';
	      liczba[i+1]++;	      
	    }
	 else liczba[i]=x+'0';
	 x=(int)(liczba[i+1]-'0') + (int)(X.liczba[i+1]-'0');
       }
  
  if (x>9 && liczba.length()==X.liczba.length())
      {
        liczba[X.liczba.length()-1]=(x-10)+'0';
	liczba+='1';
	return *this;
      }      
      
  if (x>9 && len!=lenmax)
      {
        liczba[X.liczba.length()-1]=(x-10)+'0';
	liczba[X.liczba.length()]++;
	x = liczba[X.liczba.length()] - '0';
      }
   else
      {
        liczba[X.liczba.length()-1]=x+'0';
	x = liczba[X.liczba.length()] - '0';
      }
	
  for (int i=X.liczba.length(); i<lenmax-1; i++)  //rozne liczby
      {
         if (x>9)
	    {
	      liczba[i]=(x-10)+'0';
	      liczba[i+1]++;	      
	    }
	 else 
	    {
	       liczba[i]=x+'0';
	       return *this;
	    }
	 x=(int)(liczba[i+1]-'0');        
      }
 if (x>9)
   {
     liczba[lenmax-1]=(x-10)+'0';
     liczba+='1';
   } :-| 
return *this;
}
To działa. I tak to mniej więcej trzeba pisać. To może nie jest idealnie napisane ale widać mniej więcej o co chodzi. ;) Powodzenia. W razie problemów pisz.

EDIT: Nie możesz zmieniać strincgów na inty albo nawet na long long inty bo one zdaje się mają długość 8 bajtów. A Ty chcesz dużo większe liczby. int (i każdy inny typ) ma swoją określoną pojemność. Stringa ogranicza tylko pamięć. Powodzenia ;)
kristof
Posty: 16
Rejestracja: 10 października 2007, 09:05

Post autor: kristof »

powiem szczerze, że dodawanie jakoś wcześniej sam rozgryzłem w następujący sposób

Kod: Zaznacz cały

int SUMA (int number1[],int number2[])
	{
						
	int suma, result[MAX];
	int przechowaj, i, j ;	
	
						przechowaj=0;
						for(i=MAX-1;i>=0;i--)
							{
								result[i]=number1[i] + number2[i] + przechowaj;
								przechowaj=0;
								if(result[i]>=10 && i!=0)
									{
										result[i]=result[i]-10;
										przechowaj=1;
									}
								
								//printf("petla wyn%d\n",result[i]);
							}
							printf("wynik z dodawania \n");
						for(j=0;j<MAX;j++)
							printf("%d",result[j]);
					
					printf("\n");
				
		return 0;	
	}
dlatego ciągle kombinowałem jak to zamienić na inta ;) jak widać wyżej poszedłem po najmniejszej lini oporu...
a teraz siedzę i kwiczę nad mnożeniem chociaż już wiem że łatwo to zrobić sumując n razy liczbę którą chcę pomnożyć, bo pomysłu na zapis mnożenia pisemnego dalej nie mam ;/ kurcze jakoś mam tą blokadę, że jak pracuje na liczbach to potrzebuje liczb (czyli zmiennych int double itp ) i bez tego nie mam odpowiedniego kopa do pracy.
Dziękuje za pomysł trochę mi to rozjaśniło aczkolwiek wszystkiego nie rozumiem -> np jak wpisujesz dane ? bo korzystasz ze structur liczba przy tym, gdzie potem szczytujesz jej długość (np definicja z ilu cyfr ma się składać dana liczba?)
ale już kompletnie nie rozumiem tego zapisu

Kod: Zaznacz cały

X.liczba.length()
nie wiem co on oznacza :/ do czego się odnosi...
w sumie tak jak przeglądam tą część kodu to chyba bez structur w tym programie ani rusz ?
Immortal
Posty: 31
Rejestracja: 11 grudnia 2007, 12:15
Lokalizacja: Kraków

Post autor: Immortal »

No dobra to od początku :) To jest klasa Cliczba czy jak ją tam nazwałem. Tu wklejam kawałek nagłówka (właściwie to od tego powinienem zacząć) :

Kod: Zaznacz cały

#include <string>

class CLiczby
{
private:
  string liczba; 
  CLiczby mul(int x); //mnozenie u mnie wykorzystywało tę funkcję, mnoży ona liczbę liczba(tego                  
                                   //stringa linijke wyzej przez jedną cyfrę (int x)
public:
  CLiczby();
  CLiczby(const string X);
   CLiczby(const unsigned int x);.
  CLiczby(const CLiczby & X); //jakieś konstruktory
  ~CLiczby();
  
  CLiczby & operator+=(const CLiczby &X);
//tu reszta operatorów // ciach//
  bool operator==(const CLiczby &X) const;
// tu reszta operatorów boolowskich  //ciach ;) //
  
  friend ostream & operator<<(ostream &output,const  CLiczby &X);
  friend istream & operator>>(istream &input, CLiczby &X);  
};
X.liczba.length() to funkcja zwracająca długość stringa (bo liczba jest stringiem).
wczytywanie i wypisywanie robię tak :

Kod: Zaznacz cały

ostream & operator<<(ostream & output, const CLiczby &X)
/** Operator <<. Wyprowadza liczbe na strumien wyjscia. */
{
  for (int i=X.liczba.length(); i>=0; i--)
     output << X.liczba[i];                      // odwroc liczbe
     
  return output;
}

istream & operator>>(istream & input, CLiczby &X)
/** Operator >>. Wczytuje liczbe ze strumienia wejscia. */
{
   string s;    // pomocnicza zmienna
   input >> s;  // wczytaj liczbe
   X.liczba=""; // ustaw na pusty ciag
   
   for (int i=s.length()-1; i>=0; i--)  
       {
          assert(s[i]-'0'>=0 && s[i]-'0'<=9);    // sprawdz czy nie ma niedozwolonych znakow
          X.liczba+=s[i];                        // w ten sposob odwracami liczbe
       }
  if (X.liczba=="0") return input;
  while (X.liczba[X.liczba.length()-1]=='0') X.liczba.erase(X.liczba.length()-1); // usun ewentualne 0 na poczatku      
  if (X.liczba=="") X.liczba="0";
  return input;
  
}
Dzięki temu jak napiszę w programie tak :

Kod: Zaznacz cały

Cliczba L1, L1;
cout << "Podaj 2 duże liczby :" ;
cin >> L1 >> L2;
L1+=L2;
cout << "Suma tych liczb to : << L1;
To zadziała to dokładnie tak jakbym operował na intach :) Tyle że przypisanie L1=jakiś_int nie zadziała bez przeładowania odpowiedniegop operatora.

EDIT: To co napisałeś post wyżej (ta funkcja sumująca) jest źle ;)

EDIT2 : Mnożenie będzie Ci chyba najłatwiej napisać w ten sposób co ja napisałem. A zrobiłem to tak:
Biorę pierwszą liczbę. Zapisuję ją gdzieś. teraz jadąc od tyłu drugiej liczby w każdej iteracji mnożę przez jedną cyfrę dodaję dpowiednią ilość 0 na końcu i dodaje. Rozpisz sobie na kartce normalne pisemne mnożenie to zobaczysz jak to działa ;)
kristof
Posty: 16
Rejestracja: 10 października 2007, 09:05

Post autor: kristof »

sorka ale to dodawanie działa dla każdej liczby jaką wpisałem, i zawsze wychodziły mi poprawne wyniki -> tzn nie sprawdzałem wyniku programu z moim jeśli chodziło o diabelnie duże liczby, ale takie co mogę ze spokojem na kalkulatorze dodać to zawsze mam takie same wyniki -> więc to według mnie działa poprawnie...
EDIT2 : Mnożenie będzie Ci chyba najłatwiej napisać w ten sposób co ja napisałem. A zrobiłem to tak:
Biorę pierwszą liczbę. Zapisuję ją gdzieś. teraz jadąc od tyłu drugiej liczby w każdej iteracji mnożę przez jedną cyfrę dodaję dpowiednią ilość 0 na końcu i dodaje. Rozpisz sobie na kartce normalne pisemne mnożenie to zobaczysz jak to działa ;)
szczerze też tak kombinuję, siedziałem nad tym wczoraj do 1 i zawiesiłem się właśnie na tym dopisywaniu zer. Wiem że muszę w tym celu sprzęgnąć ze sobą dwie pętle tylko..no właśnie tutaj nie wiem dokładnie jak to zrobić -> po prostu łapie taką typowo głupią zawieszkę, ale posiedzę dziś jeszcze nad tym z jeszcze większą stertą papierów i z Twoimi radami w końcu dojadę do tego z czym to połączyć by zaczął chłopak mnożyć ;) narazie nowe wyniki zapisuje na starych ale to przez brak właśnie tego przejścia z zerem ...

W końcu wszystkiego da się nauczyć komputer :)
Immortal
Posty: 31
Rejestracja: 11 grudnia 2007, 12:15
Lokalizacja: Kraków

Post autor: Immortal »

kristof pisze:sorka ale to dodawanie działa dla każdej liczby jaką wpisałem, i zawsze wychodziły mi poprawne wyniki -> tzn nie sprawdzałem wyniku programu z moim jeśli chodziło o diabelnie duże liczby, ale takie co mogę ze spokojem na kalkulatorze dodać to zawsze mam takie same wyniki -> więc to według mnie działa poprawnie...
Sorry, źle popatrzyłem na ten program wcześniej :) To rzeczywiście ma szanse działać. Tylko To zajmuje strasznie dużo pamięcie niepotrzebnie. Lepiej to zrobić na stringach. Wtedy każda liczba zajmuje tyle ile naprawde zajmuje a nie niewiadomo ile :) To MAX pewnie ustawiłeś na bardzo dużo. W tych tablicach przechowujesz inty. Spokojnie możesz je zmienić na chary. Char zajmuje tylko 1 bajt a int chyba 4. Tak w ogóle to lepiej by to robić na stringach albo dynamicznie ]
for (int i=0; i<10000; ++i)
{
long long x1, x2, x3;
x1=rnd();
x2=rnd();
x3=x1+x2
cout << x1 << " " << x2 << " " <<x3 << endl;
}[/code]
I teraz z konsoli uruchamiesz program :

Kod: Zaznacz cały

./generuj_test > pliczek
Drugi program piszesz już tak że wczytuje cin'em 3 liczby dodaje pierwsze 2 i porównuje z trzecią. Jeśli zgadza się to np nic nie wypisuje a jeśli źle to wypisuje pierwsze 2 liczby i możesz sprawdzić dla jakiego przykładu się wywala. Ja nie miałem z tym problemów bo wszystko działało na stringach i miałem przeładowany operator ==. Potem ten program uruchamiasz tak :

Kod: Zaznacz cały

./sprawdz < pliczek > plik_z_blendami
I w tym momencie błyskawicznie masz wygenerowany losowy test dla 100000 przykładów. Możesz zliczyć dobre i zle i policzyć ile procent jest dobrze ;) ja tak sprawdzałem mnożenie :) Tylko przy mnożeniu musisz uważać bo jeżeli jedna liczna ma n cyfr a druga m to wynik może mieć n+m cyfr także test generujesz wtedy na longach a wyniki na long longach. Powodzenia ;)
ODPOWIEDZ