Wie kann ich in C mit Strings rechnen?

3 Antworten

In C kannst Du mit char genauso rechnen wie mit int. Die Werte für '0' bis '9' sind lückenlos aufsteigend (ich weiß nicht, ob das so garantiert ist). Also musst Du von der Summe '4'+'3' nur einmal die '0' wieder abziehen, um das Ergebnis als Zeichen '7' zu bekommen. Bei einem Überlauf ist das Ergebnis größer als '9'. Dann ziehst Du 10 ab und merkst Dir den Übertrag. Ein einstelliger Addierer geht damit so:

// Beispiel: x = '5'; y = '9'; carry = 0;

z = x + y - '0' + carry;
carry = z>'9';
if ( carry )
    z -= 10;

// Ergebnis: z = '4'; carry = 1

Und das Ganze in eine Funktion gepackt sieht dann so aus:

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

char * decadd ( char const * x, char const * y )
{
    char const * xe = x+strlen(x);
    char const * ye = y+strlen(y);
    int const len = (xe-x>ye-y ? xe-x : ye-y)+1;
    char * z = malloc(len+1);
    z[len] = '\0';
    int carry = 0;
    for ( char *ze=z+len-1; ze>z; --ze )
    {
        *ze = (xe>x ? *--xe : '0')
            + (ye>y ? *--ye : '0')
            - '0' + carry;
        carry = *ze > '9';
        if ( carry )
            *ze -= 10;
    }
    z[0] = carry + '0';
    int zeroes = strspn(z,"0");
    if ( zeroes==len )
       --zeroes;
    memmove( z, z+zeroes, len-zeroes+1 );
    return z;
}

wie Du siehst, macht das Rückwärtslaufen in drei Strings unterschiedlicher Länge die meiste Arbeit. Wenn Du dann noch Kommazahlen addierern willst, wird das Ganze natürlich noch aufwendiger.

Zum Testen kriegste noch meine main():

int main ( int argc, char * const * argv )
{
    char * result = strdup(argv[1]);
    for ( int i=2; i<argc; ++i )
    {
        char * temp = decadd( result, argv[i] );
        //printf( "\t'%s'+'%s'='%s'\n", result, argv[i], temp );
        free(result);
        result = temp;
    }
    printf( "%s\n", result );
    free(result);
    return 0;
}

Testfälle:

gcc -Wall -o decadd decimal.c
./decadd 1 3 5 7 9

25

./decadd 1 9999999999999999999999999999999999999999999999999999999999999999

10000000000000000000000000000000000000000000000000000000000000000

./decadd $(seq 100000)

5000050000

./decadd $(seq 140000)

9800070000

Mehr passt unter Linux leider nicht auf die Kommandozeile. Aber selbst bei dieser Unmenge an Additionen merkt man noch keine Verzögerung.


da gibts schon Funktionen atof und ähnliches. Heißt ASCII nach Fließkomma. Kann nur sein, dass du das Komma in einen Punkt verwandelt musst vorher, da die Funktion von Englischer Dezimalpunktschreibweise ausgeht.


MeisterDerProfi 
Fragesteller
 04.12.2022, 17:36

ne an sich möchte ich eigenlich selber eine funktoin schreiben die 2 stringzahlen addiert ohne atof, weil der sinn der sache ist es, mit sehr großen zahlen zu rechnen, ohne dass rundungsfehler entstehen. wie hoch wäre der aufwand das manuell zu machen?

0
iqKleinerDrache  04.12.2022, 17:38
@MeisterDerProfi

großer Aufwand. Weil du ja auch nicht einfach zwei Integer nehmen kannst .. die sind ja auch begrenzt. Wenn das aber bei dir kein Problem ist, weil du weißt dass die Vorkommastellen und Nachkommastellen in den vom Compiler größten unterstützten Integer Wert passt, dann ist es leichter.

1
KarlRanseierIII  04.12.2022, 19:39
@MeisterDerProfi

Wenn es Dir nur um die Addition geht und Du das in Fixed-Point selbst ausführst, dann ist der Aufwand überschaubar.

Für Deine eigentliche Anforderung gibt es extra multiprecision und arbitrary precision libraries.

1
iqKleinerDrache  04.12.2022, 19:43
@KarlRanseierIII

ich hab sowas schon mal mit nur ganzzahlen dafür aber 200 und mehr länge gemacht ... war nicht so einfach. aber auch multiplation, division und subtraktion

2

Du kannst die Strings in ein Zahlenformat konvertieren, das geht normalerweise mit einer einfachen Funktion. Dann kannst du die beiden Zahlen addieren und wieder in einen String umwandeln. Als Zahlenformat empfehle ich double, die Konvertierung kann man da mit der Funktion atof() machen.