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

Kalkulator dużych liczb całkowitych

Ostatnio zmodyfikowano 2017-01-12 08:04
Autor Wiadomość
Beli
Temat założony przez niniejszego użytkownika
Kalkulator dużych liczb całkowitych
» 2016-12-27 12:31:56
Mam problem z projektem zaliczeniowym w języku C. Chodzi o kalkulator dwóch dowolnych liczb całkowitych (dodawanie, odejmowanie, mnożenie i dzielenie), ale tylko tych 32-cyfrowych. Radzę sobie jak na razie raczej kiepsko i już samo dodawanie sprawiło mi kłopot. Nie wiem czy istnieje jakaś sprytna metoda z wykorzystaniem stosów na to zadanie, w każdym razie ja starałem się naśladować dodawanie pod kreską.

C/C++
#include <stdio.h>
#include <stdlib.h>

int Dodawanie( char X[], char Y[], char Z[] )
{
    int i, suma;
    int p = 0;
    for( i = 31; i >= 0; i-- )
    {
        suma = X[ i ] + Y[ i ] + p;
        Z[ i ] = suma % 10;
        p = suma / 10;
    }
    return p;
}
int main()
{ int i;
    printf( "Podaj pierwsza liczbe 32-cyfrowa: \n" );
    char A[ 32 ];
    scanf( "%s", A );
    printf( "Twoja liczba to: " )
    for( i = 0; i < 32; i++ )
         printf( "%d", A[ i ] - 48 );
   
    printf( "\nPodaj druga liczbe 32-cyfrowa: \n" );
    char B[ 32 ];
    scanf( "%s", B );
    printf( "Twoja liczba to: " )
    for( i = 0; i < 32; i++ )
         printf( "%d", B[ i ] - 48 );
   
    printf( "\n" );
    char C[ 33 ];
    for( i = 0; i <= 32; i++ )
         C[ i ] = 0; /* zerowanie tablicy C */
   
    Dodawanie( A, B, C );
    for( i = 31; i >= 0; i-- )
         printf( "%d", C[ i ] );
   
    return 0;
}
Jak na razie chodzi mi tylko o to, co robię nie tak (a jestem pewien że całkiem sporo), że wynik wychodzi kompletnie inny niż powinien. Odejmowaniem, mnożeniem i dzieleniem zajmę się później, jakimś interfejsem tak samo - podejrzewam że w kilku miejscach w podprogramie Dodawanie mogłem po prostu pomylić int z charem, tudzież nie zastosować wskaźników, ale nie czuję tego i nie potrafię samodzielnie wyłapać. Nie jestem też pewien jak uwzględnić sytuację, gdy wynikiem dodawania będzie liczba 33-cyfrowa, a że chodzi o liczby całkowite, a nie naturalne, to dochodzi jeszcze problem z wynikami ujemnymi, no i przez to zaczynam się zastanawiać patrząc na te moje wypociny czy nie proszę Was tutaj o reanimację trupa :D
P-155510
mateczek
» 2016-12-27 12:54:11
sprytny istnieje. biblioteka gmp :)
https://www.youtube.com/watch?v=Mr6yAf9XpE0&t=3s

A błędów szukaj debuggerem
P-155512
latajacaryba
» 2016-12-27 12:58:09
Tablica C chyba nie jest pusta (nie wypełniona zerami)
weź wszystko w komentarz i wyświetl samą tablicę C, to zobaczysz co wyjdzie. To pewnie to psuje wynik
P-155513
mateczek
» 2016-12-27 13:20:09
W C u mnie kiepsko.
1 Ale błąd masz ewidentny licząc cyfrę z tablicy char !!!!
2 Drugi błąd to wydaje mi sie, że zakładasz iż obie liczby mają stałą długość i w dodatku równą . Liczbę po wczytaniu do tablicy musiał byś wyrównać do prawej strony tej tablicy. I dopiero potem dodawać w sposób, który sobie wybrałeś

C/C++
#include <iostream>
using namespace std;

string Dodawanie( string X, string Y )
{
    int p = 0;
    string wynik;
    int indexX = X.size() - 1; //index na ostatni elemetn liczby
    int indexY = Y.size() - 1; //index na ostatni elemetn liczby
    int _x, _y; //poszczególne cyfry ciągu x oraz y
    while(( indexX >= 0 ) ||( indexY >= 0 ) ||( p > 0 ) ) //gdy obie liczby się już skończą
    {
        if( indexX >= 0 ) {
            _x = X[ indexX-- ] - '0'; //tak liczyć cyfrę ze stringa lub tablicy char. od wartości stringa odjąć '0'
        }
        else _x = 0; //gdy jedna liczba się skończyła przyjmuj cyfry jako zera
       
        if( indexY >= 0 ) {
            _y = Y[ indexY-- ] - '0';
        }
        else _y = 0; //gdy druga liczba się skończyła przyjmuj cyfry jako zera  
       
        int suma = p + _x + _y; //to jak u ciebie
        int cyfra = suma % 10; //to również jak u ciebie
        p = suma / 10; // to również bez zmian
        wynik.insert( wynik.begin(), cyfra + '0' ); //wyliczoną cyfrę wstawiam na początek stringu. Ale można na koniec, a potem odwrócić będzie wydajniej
       
    }
    return wynik;
}
int main() {
    string l1 { "1232" };
    string l2 { "121" };
    string w = Dodawanie( l1, l2 );
    cout << w;
   
}
P-155515
Beli
Temat założony przez niniejszego użytkownika
» 2016-12-27 14:16:17
Nie jestem pewien czy biblioteka gmp przejdzie - prowadzący zakłada że program musi się przynajmniej skompilować, jeśli uda mi się ją jakoś zaimplementować u siebie będzie ona również działała u niego przy sprawdzaniu?

@latajacaryba - zrobiłem tak jak pisałeś, rzeczywiście nie była wyzerowana. Uzupełniłem to w kodzie u góry, mam nadzieję że dobrze, ale nadal wyniki nie są poprawne, więc musiałem pomylić się jeszcze gdzieś.
@mateczek - nie bardzo rozumiem, w którym konkretnie miejscu popełniam błąd licząc cyfrę z tabeli char? W mainie, w podprogramie?
A co do długości liczb - nie wiem czy dobrze rozumiem, ale wg polecenia tak chyba właśnie jest, obie liczby mają stałą i równą długość, są 32-cyfrowe - to chyba takie ułatwienie ze strony prowadzącego.
P-155521
mateczek
» 2016-12-27 14:28:25
C/C++
//ty masz tak
suma = X[ i ] + Y[ i ] + p;

//ja upraszczając  zrobiłem tak
_x = X[ i ] - '0'; //tak liczyć cyfrę ze stringa lub tablicy char. od wartości stringa odjąć '0'
_y = Y[ i ] - '0';
int suma = p + _x + _y; //to jak u ciebie

char A[ 32 ]; //tablica powinna uwzględniać miejsce na terminator C-stringa czyli powinna być o jeden większa od oczekiwanej długości łańcucha!!!
i zdecyduj się czy robisz na liczbach czy na znakach !!!


//edit
powinno być jakoś tak rozmiar dałem na 5;
C/C++
#include <stdio.h>
#include <stdlib.h>

int Dodawanie( char X[], char Y[], char Z[], int size )
{
    int i, suma;
    int p = 0;
    Z[ size + 1 ] = '\0';
    for( i = size - 1; i >= 0; i-- )
    {
        suma = X[ i ] - '0' + Y[ i ] - '0' + p;
        Z[ i + 1 ] = suma % 10 + '0';
        p = suma / 10;
    }
    Z[ 0 ] = p + '0';
    return p;
}
int main()
{
    const int size = 5; //w C chyba nie m a const ?? więc sobie popraw !!!
    char A[ size + 1 ] { "99999" };
    char B[ size + 1 ] { "11111" };
    char C[ size + 2 ];
    Dodawanie( A, B, C, 5 );
    printf( "%s,", C );
    return 0;
}
P-155524
mokrowski
» 2016-12-27 23:29:42
Masz i baw się... jakoś w tym stylu bym to popełnił...
C/C++
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#define MAX_POSITIONS 32

void read_value_string( char * values_s ) {
    printf( "Podaj %u pozycyjną liczbę dodatnią całkowitą: ", MAX_POSITIONS );
    scanf( " %" MAX_POSITIONS "s", values_s );
}

void convert_string_to_values( char const * values_s, unsigned * values_u ) {
    size_t string_length = strlen( values_s );
    size_t offset = MAX_POSITIONS - string_length - 1;
    for( size_t i = string_length; i != 0; --i ) {
        char letter = values_s[ i - 1 ];
        if( !isdigit( letter ) ) {
            fprintf( stderr, "Znak '%c' na pozycji %zu nie jest cyfrą.\n", letter, i );
            exit( EXIT_FAILURE );
        }
        values_u[ offset + i ] =( unsigned )( letter - '0' );
    }
}

void add_values( unsigned * src1, unsigned * src2, unsigned * dst ) {
    // XXX: Rozmiar dst powinien być o 1 pozycję większy niż src1 lub src2.
    // Rozmiar src1 i src2 powinien być równy MAX_POSITIONS.
    unsigned carry = 0;
    unsigned sum;
    for( size_t i = MAX_POSITIONS; i != 0; --i ) {
        sum = src1[ i - 1 ] + src2[ i - 1 ] + carry;
        carry = sum / 10;
        sum %= 10;
        dst[ i ] = sum;
    }
    dst[ 0 ] = carry;
}

// Zwraca wskaźnik na pierwszy znak "nie zero"
char * convert_values_to_string( unsigned * value, char * value_s, size_t length ) {
    // XXX: Rozmiar values_s powinien być większy o 1 od length aby zawierać \0 kończące string.
    value_s[ length ] = '\0';
    for( size_t i = length; i != 0; --i ) {
        unsigned val = value[ i - 1 ];
        if( val > 9 ) {
            fprintf( stderr, "Błąd wartości %u na pozycji %zu.\n", val, i );
            exit( EXIT_FAILURE );
        }
        value_s[ i - 1 ] = '0' + val;
    }
    size_t count = 0;
    for(; count <( length + 1 ); ++count ) {
        if( value_s[ count ] != '0' ) {
            break;
        }
    }
    return &( value_s[ count ] );
}

void read_value( unsigned * value ) {
    char * value_s =( char * ) malloc(( MAX_POSITIONS * sizeof( char ) ) + 1 );
   
    memset( value_s, 0,(( MAX_POSITIONS * sizeof( value_s[ 0 ] ) ) + 1 ) );
    memset( value, 0,( MAX_POSITIONS * sizeof( value[ 0 ] ) ) );
   
    read_value_string( value_s );
    convert_string_to_values( value_s, value );
   
    free( value_s );
}

int main() {
    unsigned value1[ MAX_POSITIONS ];
    unsigned value2[ MAX_POSITIONS ];
    // Tylko dodawanie więc o 1 element większy...
    unsigned result[ MAX_POSITIONS + 1 ];
   
    printf( "Liczba 1: " );
    read_value( value1 );
    printf( "Liczba 2: " );
    read_value( value2 );
   
    printf( "Dodawanie liczb:\n" );
    add_values( value1, value2, result );
   
    // String zawierający wynik dodawania
    char result_s[ MAX_POSITIONS + 2 ];
    char * str_ptr = convert_values_to_string( result, result_s, MAX_POSITIONS + 1 );
    // Wyświetlenie z wiodącymi zerami
    printf( "%s\n", result_s );
    // Wyświetlenie bez wiodących zer
    printf( "%s\n", str_ptr );
   
    return EXIT_SUCCESS;
}
P-155577
Beli
Temat założony przez niniejszego użytkownika
» 2016-12-28 17:03:23
Dziękuję, bardzo mi to pomogło. Spróbowałem zrobić odejmowanie wg schemat mateczka, nie bardzo mam tylko pomysł na dokończenie.
C/C++
int Odejmowanie( char X[], char Y[], char Z[], int SIZE )
{
    int i, roznica;
    int p = 0;
    Z[ SIZE + 1 ] = '\0';
   
    for( i = SIZE - 1; i >= 0; i-- )
    {
        roznica = X[ i ] - '0' - Y[ i ] + '0' + p;
        Z[ i + 1 ] = roznica % 10 + '0';
        p = roznica / 10; /* jesli wyszlo 0 to nic nie robie, kontynuuje petle. jesli nie to chce zmienic instrukcje dla petli na te ponizej. jezli tam wyjdzie 0 to wracam do starych instrukcji, jezli nie to kontynuuje nowe. Moze jest prostszy sposob? */
        if( p == 0 );
        else
        {
            roznica = X[ i ] - '0' - Y[ i ] + '0' + p;
            Z[ i + 1 ] = roznica % 10 + 10 + '0';
            p = roznica / 10 - 1;
        }
    }
   
    Z[ 0 ] = p + '0'; /* to w odejmowaniu nie ma chyba znaczenia? */
    return p;
}
Ogółem wszystko działa wtedy, gdy nie korzystam w ogóle ze zmiennej p (innymi słowy p=0), tj. nie ma konieczności "pożyczania" wartości od wyższych rzędów, np. dla 55555-44444. Wtedy korzystamy po prostu z tego fragmentu:
C/C++
roznica = X[ i ] - '0' - Y[ i ] + '0' + p;
Z[ i + 1 ] = roznica % 10 + '0';
p = roznica / 10;
Jeśli jest konieczność "pożyczenia" wartości z rzędu wyższego, tzn. p jest jakąś liczbą ujemną, trzeba zmienić instrukcję w pętli na taką:
C/C++
roznica = X[ i ] - '0' - Y[ i ] + '0' + p;
Z[ i + 1 ] = roznica % 10 + 10 + '0';
p = roznica / 10 - 1;
No ale mam problem żeby to zaprogramować - moja idea jest taka jak w kodzie u góry, jeśli p=0 to nie robimy nic, po prostu kontynuujemy pętlę for. Jeśli natomiast p nie jest równe 0, to należy zmienić instrukcję pętli na taką jak powyżej napisałem. Jeżeli po wykonaniu obrotu tej pętli otrzymamy p=0 to wracamy do pierwotnych instrukcji pętli, jeśli p inne niż 0 to dalej robimy tę nową instrukcję. Wydaje mi się że algorytm jest poprawny, ale nie wiem jak mogę go zamienić na kod w C. Chciałem posłużyć się if-em i dla p==0 zastosować instrukcję pustą. Ale co dać w else żeby działało to zgodnie z oczekiwaniami? A może ktoś ma jakiś prostszy pomysł na rozwiązanie tego?

//edit: już sobie poradziłem, w bardzo prosty sposób, działa poprawnie dla dowolnych liczb naturalnych pod warunkiem że pierwsza jest wieksza od drugiej, ale powiedzmy że tu wystarczy odwrócić kolejność i wstawić minus przed wynikiem:
C/C++
int Odejmowanie( char X[], char Y[], char Z[], int SIZE )
{
    int i, roznica;
    int p = 0;
    Z[ SIZE + 1 ] = '\0';
   
    for( i = SIZE - 1; i >= 0; i-- )
    {
        roznica = X[ i ] - '0' - Y[ i ] + '0' + p;
        if( roznica >= 0 )
        {
            Z[ i + 1 ] = roznica % 10 + '0';
            p = roznica / 10;
        }
        else
        {
            Z[ i + 1 ] = roznica % 10 + 10 + '0';
            p = roznica / 10 - 1;
        }
    }
    Z[ 0 ] = p + '0'; /* to w odejmowaniu nie ma chyba znaczenia? */
    return p;
}
P-155596
« 1 » 2
  Strona 1 z 2 Następna strona