diff --git a/a3-6/README.md b/a3-6/README.md new file mode 100644 index 0000000..6abe29b --- /dev/null +++ b/a3-6/README.md @@ -0,0 +1,130 @@ +# 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. + +```c +#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. + +```c +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. + +```c +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. + +```c +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`: + +```c +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 \ No newline at end of file diff --git a/a3-6/ansatz1/int20.c b/a3-6/ansatz1/int20.c new file mode 100644 index 0000000..534d7b7 --- /dev/null +++ b/a3-6/ansatz1/int20.c @@ -0,0 +1,54 @@ +#include +#include "int20.h" + +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; +} + +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] + b.digits[i] - '0' + carry; + carry = 0; + + if (cd > '9') { + cd -= 10; + carry = 1; + } + + c.digits[i] = cd; + } + if (carry != 0) { + printf("INT20 OVERFLOW\n"); + } + return c; +} + + +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]); + } +} \ No newline at end of file diff --git a/a3-6/ansatz1/int20.h b/a3-6/ansatz1/int20.h new file mode 100644 index 0000000..5bc356f --- /dev/null +++ b/a3-6/ansatz1/int20.h @@ -0,0 +1,12 @@ +#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 \ No newline at end of file diff --git a/a3-6/ansatz1/main.c b/a3-6/ansatz1/main.c new file mode 100644 index 0000000..0e630bf --- /dev/null +++ b/a3-6/ansatz1/main.c @@ -0,0 +1,40 @@ +#include +#include "int20.h" + +int main(void) { + struct int20 a= create20("12345678901234567890"); + struct int20 b= create20("100"); + struct int20 sum= add20(a, b); + print20(a); printf("\n"); + print20(b); printf("\n"); + print20(sum); printf("\n"); + + printf("\n\n"); + + a = create20("9700"); + b = create20("422"); + sum = add20(a, b); + print20(a); printf("\n"); + print20(b); printf("\n"); + print20(sum); printf("\n"); + + printf("\n\n"); + + a = create20("99999999999999999999"); + b = create20("123456789"); + sum = add20(a, b); + print20(a); printf("\n"); + print20(b); printf("\n"); + print20(sum); printf("\n"); + + printf("\n\n"); + + print20(create20("1")); printf("\n"); + print20(create20("0")); printf("\n"); + + printf("\n\n"); + + print20(add20(create20("1338"), create20("99999999999999999999"))); + + printf("\n"); +} \ No newline at end of file diff --git a/a3-6/ansatz2/int20.c b/a3-6/ansatz2/int20.c new file mode 100644 index 0000000..a3c9002 --- /dev/null +++ b/a3-6/ansatz2/int20.c @@ -0,0 +1,54 @@ +#include +#include "int20.h" + +struct int20 create20(char val[]) { + // int20 deklarieren + struct int20 num; + + // Länge des übergebenen Strings herausfinden. Maximal 20 + int length = 0; + for (; length < 20 && val[length] != '\0'; length++); + + // num.digits mit den übergebenen Ziffern auffüllen, bzw mit '0' + for (int i = 0; i < 20; i++) { + if (i < 20 - length - 1) { + num.digits[i] = 0; + } else { + num.digits[i] = val[i - 20 + length]; + } + } + + return num; +} + +struct int20 add20(struct int20 a, struct int20 b) { + struct int20 c; + + int carry = 0; + for (int i = 19; i >= 0; i--) { + + char cd = a.digits[i] + b.digits[i] - '0' + carry; + carry = 0; + + if (cd > '9') { + cd -= 10; + carry = 1; + } + + c.digits[i] = cd; + } + if (carry != 0) { + printf("INT20 OVERFLOW\n"); + } + return c; +} + + +void print20(struct int20 num) { + int i = 0; + for (; i < 20 && num.digits[i] == '0'; i++); + if (i >= 20) printf("0"); + for (; i < 20; i++) { + printf("%c", num.digits[i]); + } +} \ No newline at end of file diff --git a/a3-6/ansatz2/int20.h b/a3-6/ansatz2/int20.h new file mode 100644 index 0000000..222c12b --- /dev/null +++ b/a3-6/ansatz2/int20.h @@ -0,0 +1,12 @@ +#ifndef HEADER_INT20 +#define HEADER_INT20 + +struct int20 { + char digits[21]; +}; + +extern struct int20 create20(char val[]); +extern struct int20 add20(struct int20 a, struct int20 b); +extern void print20(struct int20 num); + +#endif \ No newline at end of file diff --git a/a3-6/ansatz2/main.c b/a3-6/ansatz2/main.c new file mode 100644 index 0000000..0e630bf --- /dev/null +++ b/a3-6/ansatz2/main.c @@ -0,0 +1,40 @@ +#include +#include "int20.h" + +int main(void) { + struct int20 a= create20("12345678901234567890"); + struct int20 b= create20("100"); + struct int20 sum= add20(a, b); + print20(a); printf("\n"); + print20(b); printf("\n"); + print20(sum); printf("\n"); + + printf("\n\n"); + + a = create20("9700"); + b = create20("422"); + sum = add20(a, b); + print20(a); printf("\n"); + print20(b); printf("\n"); + print20(sum); printf("\n"); + + printf("\n\n"); + + a = create20("99999999999999999999"); + b = create20("123456789"); + sum = add20(a, b); + print20(a); printf("\n"); + print20(b); printf("\n"); + print20(sum); printf("\n"); + + printf("\n\n"); + + print20(create20("1")); printf("\n"); + print20(create20("0")); printf("\n"); + + printf("\n\n"); + + print20(add20(create20("1338"), create20("99999999999999999999"))); + + printf("\n"); +} \ No newline at end of file