|
||
---|---|---|
.. | ||
ansatz1 | ||
ansatz2 | ||
README.md |
README.md
A3-6 Ergebnisse
20 Ziffern lange Integer als Strings speichern, und mit diesen rechnen
Zunächst wird das struct int20
definiert. Dies erfolgt in der int20.h
Header Datei.
Um eine Mehrfachdefinition zu vermeiden, werden hier die Präprozessoranweisungen #ifndef
und #define
verwendet.
Des Weiteren, werden hier die Funktionen create20
, add20
und print20
deklariert.
#ifndef HEADER_INT20
#define HEADER_INT20
struct int20 {
char digits[20];
};
extern struct int20 create20(char val[]);
extern struct int20 add20(struct int20 a, struct int20 b);
extern void print20(struct int20 num);
#endif
create20
Die create20
Funktion, erstellt aus einem char *
einen int20
. Hierbei wird das \0
Byte aus der Zeichenkette entfernt, sodass digits
ausschließlich Ziffern von 0 bis 9 enthält.
Außerdem wird die Reihenfolge der Ziffern vertauscht, und alle Ziffern, die über die Länge der ursprünglichen Zahl hinnaus gehen, werden mit '0'
aufgefüllt. Dies hat den Effekt, dass der Wert jeder Ziffer durch 10^i * d
ausgedrückt werden kann, wobei d
die Ziffer und i
der Index ist, an der sich die Ziffer im Array befindet. Die Zahl 1337
würde also im Speicher als 73310000000000000000
stehen. Der Verständlichkeit halber, kann man sich das Array einfach spiegelverkehrt vorstellen, sodass der Index von rechts nach links aufsteigend zählt.
struct int20 create20(char val[]) {
// int20 deklarieren
struct int20 num;
// Länge des übergebenen Strings herausfinden. Maximal 20
int maxIndex = 1;
for (; maxIndex < 20 && val[maxIndex] != '\0'; maxIndex++);
// num.digits mit den übergebenen Ziffern auffüllen, bzw mit '0'
for (int i = 0; i < 20; i++) {
if (i < maxIndex) {
num.digits[i] = val[maxIndex - i - 1];
} else {
num.digits[i] = '0';
}
}
return num;
}
print20
Die print20
Funktion ist relativ selbsterklärend. Der Inhalt des übergebenen int20
soll wieder umgekehrt werden, und führende Nullen abgeschnitten.
Hierfür wird beim Index 19
angefangen und heruntergezählt, bis eine andere Ziffer als 0
gefunden wird. Dadurch wird der Index gefunden, bei dem die Ausgabe angefangen werden soll.
Sollte die Zahl genau 0
sein, wäre dieser Index jedoch -1
. Dies muss natürlich beachtet werden.
Anschließend werden die restlichen Ziffern einfach einzeln mittels printf
ausgegeben.
void print20(struct int20 num) {
int i = 19;
for (; i >= 0 && num.digits[i] == '0'; i--);
if (i < 0) printf("0");
for (; i >= 0; i--) {
printf("%c", num.digits[i]);
}
}
Ein alternativer Implementierungsansatz könnte z.B. die Reihenfolge der Ziffern beibehalten und in dem struct int20
hinter dem char[]
einen konstanten char
einfügen, der lediglich das \0
Byte enthält. In diesem Fall könnte Ausgabe statt durch die Schleife auch einfach durch printf("%s", &num.digits[i])
erfolgen.
add20
Die add20
Funktion ist dank der umgedrehten Reihenfolge der Ziffern recht simpel.
Die Ziffern der beiden zu addierenden int20
s werden einzeln addiert und gegebenenfalls ein Übertrag mit aufaddiert.
Bei der Berechnung der Ergebnis-Ziffer wird die folgende Formel verwendet: a.digits[i] - '0' + b.digits[i] + carry
Da die Ziffern im ASCII Zeichensatz sequentiell hintereinander liegen, kann man um z.B. von '4'
auf '7'
zu kommen, einfach 2
zum char
addieren. Dies wird sich hier zu Nutze gemacht. Die Werte der beiden char
s werden einfach zusammen addiert, und der Wert von '0'
wird einmal abgezogen, da er sonst einmal zu viel addiert wird. Anschließend wird der Übertrag aus dem vorherigen Schleifendurchlauf mit übernommen.
Nun kann das Ergebnis jedoch größer als '9'
sein. In diesem Fall werden nocheinmal 10
von dem char
abgezogen, und der carry
wird für den nächsten Schleifendurchlauf auf 1
gesetzt.
Ist nach Ende der Schleife noch ein Übertrag vorhanden, so lag ein Overflow vor. Dies wird einfach auf der Konsole ausgegeben, doch das inkorrekte Ergebnis wird zurückgegeben.
struct int20 add20(struct int20 a, struct int20 b) {
struct int20 c;
int carry = 0;
for (int i = 0; i < 20; i++) {
char cd = a.digits[i] - '0' + b.digits[i] + carry;
carry = 0;
if (cd > '9') {
cd -= 10;
carry = 1;
}
c.digits[i] = cd;
}
if (carry != 0) {
printf("INT20 OVERFLOW\n");
}
return c;
}
Anmerkung:
Da ein Overflow hier mehr oder weniger Ignoriert wird, kann man mit ein wenig Trickserei auch Subtraktionen durchführen. So ist die Zahl 99999999999999999999
z.B. äquivalent zu -1
:
print20(add20(create20("1338"), create20("99999999999999999999")))
liefert als Ergebnis 1337
.
Dieses Verhalten ist mit Modulo-Berechnungen zu vergleichen, oder sogar p- bzw 10-adischen Zahlen