a3-6
This commit is contained in:
parent
126a42b2b6
commit
f1c010aef9
|
@ -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
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#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]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#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");
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#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]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#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");
|
||||||
|
}
|
Loading…
Reference in New Issue