Forum: Mikrocontroller und Digitale Elektronik Modulo und Dezimalzahl


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Helene M. (hmeyer)


Lesenswert?

1
u_in = ADC_Value * 3.3 / 255;
2
percent = (u_in / 3.3) * 100;
3
unsigned char UART_TX[5] = {0,0,0,0,0};
4
5
UART_TX[1] = (percent/100)%10+0x30; // 100er ablegen
6
UART_TX[2] = (percent/10)%10+0x30; // 10er ablegen
7
UART_TX[3] = (percent%10)+0x30; // 1er ablegen

Also was in den einzelnen Zeilen passiert, steht ja bereits dahinter, 
nur wenn ich mir das an einem konkreten Beispiel anschaue, ist es mir 
noch nicht ganz klar:
z.B. percent = 428
(428/100)%10=(4,28)%10   >> 4,28%10  also 4,28/10 ist 0 Rest 4,28

Ich nehme an, dass nur die "4" in UART_TX[1] gespeichert wird, aber wie 
funktioniert das genau?

von Rolf M. (rmagnus)


Lesenswert?

Helene M. schrieb:
> Also was in den einzelnen Zeilen passiert, steht ja bereits dahinter,
> nur wenn ich mir das an einem konkreten Beispiel anschaue, ist es mir
> noch nicht ganz klar:
> z.B. percent = 428
> (428/100)%10=(4,28)%10   >> 4,28%10  also 4,28/10 ist 0 Rest 4,28
>
> Ich nehme an, dass nur die "4" in UART_TX[1] gespeichert wird, aber wie
> funktioniert das genau?

Du hast leider vergessen, dazuzuschreiben, von welchem Typ percent ist. 
Ich vermute, dass es ein Integer-Typ ist. Dann ist 428/100 = 4.
Den %-Operator gibt es für floating-Point-Zahlen auch gar nicht. 4,28%10 
ist also nicht 4,28, sondern ein Fehler.

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Du schmeisst Float- und Integer-Berechnungen durcheinander.

Stell' einfach mal die Variablen-Definitionen mit hier ein!

von Norbert (der_norbert)


Lesenswert?

Helene M. schrieb:
> u_in = ADC_Value * 3.3 / 255;

Das stirbt wohl nie aus.

Ist das ein 7,9944 Bit ADC oder ein 8 Bit ADC?

von Rainer W. (rawi)


Lesenswert?

Helene M. schrieb:
> z.B. percent = 428
> (428/100)%10=(4,28)%10   >> 4,28%10  also 4,28/10 ist 0 Rest 4,28

Nein, (428/100) ist eine Integerdivision und als Ergebnis kommt folglich 
4 heraus.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Helene M. schrieb:
> u_in = ADC_Value * 3.3 / 255;
Diese Rechnung ist übrigens falsch. Es muss "/256" heißen, wenn es 
technisch korrekt sein soll.

Nur aus Interesse: programmierst du Arduino? Auffallend viele Beispiele 
aus dieser Ecke verwenden solche falschen Faktoren 2^n-1 (wie 255, 1023, 
2047, 4095, usw) beim Rechnen mit dem ADC.

: Bearbeitet durch Moderator
von Rolf M. (rmagnus)


Lesenswert?

Norbert schrieb:
> Ist das ein 7,9944 Bit ADC oder ein 8 Bit ADC?

Ich komme auf 7,96875.

von Norbert (der_norbert)


Lesenswert?

Rolf M. schrieb:
> Norbert schrieb:
>> Ist das ein 7,9944 Bit ADC oder ein 8 Bit ADC?
>
> Ich komme auf 7,96875.

Mag sein. Aber wie?

ln(255)/ln(2) = 7,99435343685885793758

von Wolfgang R. (Firma: www.wolfgangrobel.de) (mikemcbike)


Lesenswert?

Norbert schrieb:
> Mag sein. Aber wie?

255/256*8

von Helene M. (hmeyer)


Lesenswert?

Das ist sie:
static unsigned char percent = 0;

von Norbert (der_norbert)


Lesenswert?

Wolfgang R. schrieb:
> Norbert schrieb:
>> Mag sein. Aber wie?
>
> 255/256*8

Aber um genau diese ›8‹ geht's doch.
Die im Eröffnungsbeitrag genannte Berechnung stimmt nur dann, wenn man 
einen 7,9944 Bit ADC hat. Jede der 7,9944 Stellen kann entweder ›0‹ oder 
›1‹ annehmen. Also zwei Zustände.

2**7,9944 == 255

von Rahul D. (rahul)


Lesenswert?

Helene M. schrieb:
> Das ist sie:
> static unsigned char percent = 0;

das ist ja nun nicht die einzige Variable...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Helene M. schrieb:
> static unsigned char percent = 0;
1. Wozu static?
2. In einen unsigend char passen die beispielhaften 428 gar nicht 
rein...

Helene M. schrieb:
1
u_in = ADC_Value * 3.3 / 255;
2
percent = (u_in / 3.3) * 100;
Diese erstaunlich umständliche Berechnung ginge übrigens ganz ohne 
rechnerischen Umweg (wozu hier unnötigerweise eine Spannung ausrechnen?) 
und ohne rechenintensives float viel einfacher so:
1
percent = ((int)ADC_Value*100)/256;
Das geht sogar ganz ohne Division, weil hier das untere Byte des 
16-Bit-Integers einfach ignoriert wird. Probiers aus.

: Bearbeitet durch Moderator
von Norbert (der_norbert)


Lesenswert?

Lothar M. schrieb:
> percent = ((int)ADC_Value*100)/256;
> Das geht sogar ganz ohne Division, weil hier das untere Byte des
> 16-Bit-Integers einfach ignoriert wird. Probiers aus.

Und zur schöneren Rundung vielleicht noch:
1
((int)ADC_Value*100+128)/256;

von Rolf M. (rmagnus)


Lesenswert?

Norbert schrieb:
> Aber um genau diese ›8‹ geht's doch.
> Die im Eröffnungsbeitrag genannte Berechnung stimmt nur dann, wenn man
> einen 7,9944 Bit ADC hat. Jede der 7,9944 Stellen kann entweder ›0‹ oder
> ›1‹ annehmen. Also zwei Zustände.
>
> 2**7,9944 == 255

Stimmt. Bei meiner Rechnung wären es quasi immer noch 8 Bit, aber jedes 
Bit könnte die Werte 0 und 0.99609375 annehmen.

von Bernd (bernd_mt-09)


Lesenswert?

Wie kann ein Bit 0.99609375 sein?
Entweder 0 oder 1

von Rolf M. (rmagnus)


Lesenswert?

Bernd schrieb:
> Wie kann ein Bit 0.99609375 sein?

Aber 7,9944 Bits sind kein Problem für dich?

von Norbert (der_norbert)


Lesenswert?

Bernd schrieb:
> Wie kann ein Bit 0.99609375 sein?
> Entweder 0 oder 1

Wie kann ein ADC 7,9944 Bit haben?

Es geht hier um eine rein hypothetische Betrachtung warum die Division 
durch 255 (oder alle 2^n-1) falsch ist.

Edit: Rolf war schneller!

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Bernd schrieb:
> Wie kann ein Bit 0.99609375 sein?
> Entweder 0 oder 1

Die "1" hat einen Dezimalen-Wert von 0.99609375.
Erst wenn du da wieder alle "0" dazu zählst, wird wieder ne 1 draus! :D

von Bernd (bernd_mt-09)


Lesenswert?

Rolf M. schrieb:
> Bernd schrieb:
>> Wie kann ein Bit 0.99609375 sein?
>
> Aber 7,9944 Bits sind kein Problem für dich?

Doch damit habe ich auch ein Problem.

Aber ob nun 255 oder 256 geht doch in der Menge der Fehler zunächst mal 
unter.
Die Berechnung an sich stimmt doch schon nicht bzw. macht nicht das was 
sie machen soll und ist viel zu kompliziert. Aber das wurde doch schon 
alles gesagt.

von Rolf (rolf22)


Lesenswert?

Helene M. schrieb:

> also 4,28/10 ist 0 Rest 4,28

Nein. In Programmiersprachen hängt die Art der Division oft vom Typ der 
Variablen ab:
https://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/c_modulo_de (erste 
beiden Sätze)

float a; int b;
float c1; int c2;
a = 5.28;  b = 10;
c1 = a/b; // ergibt 0.528;
c2 = a/b; // ergibt 0, es wird also abgeschnitten, nicht gerundet.

von Rainer W. (rawi)


Lesenswert?

Rolf M. schrieb:
> Aber 7,9944 Bits sind kein Problem für dich?

Unterscheide zwischen Informationsgehalt und Wertebereich

von Rolf M. (rmagnus)


Lesenswert?

Bernd schrieb:
> Wie kann ein Bit 0.99609375 sein?

Ein Bit kann sein, was immer du willst. Zunächst einmal ist ein Bit ja 
nur eine binäre Information, kennt also zwei mögliche Zustände. Was 
diese beiden Zustände bedeuten, legt man bei der Verwendeung fest. Das 
kann z.B. true und false, 1 und 0, an und aus, links und rechts oder 
Asterix und Obelix sein - oder auch 0,99609375 und 0. Ob das sinnvoll 
ist, steht aber natürlich auf einem anderen Blatt.

von Jasson J. (jasson)


Lesenswert?

Wenn das Ganze auf einer Platform ohne Floating-Point-Unit läuft, wäre 
folgender Ansatz effizienter mit Blick auf die Laufzeit
-
Den Faktor, der bei 3.3 / 256 herauskommt mit der 10´er Potenz 
multiplizieren, dass der Faktor keine Nachkommastelle mehr hat.

Den ADC-Wert mit diesem Faktor multiplizieren - die Zielvariable muss 
natürlich ein ausreichend großer Typ sein.

Dann stimmen die Ziffern in der Zahl zumindest schon mal.
Unter dem Wissen, was der maximale Wert ist, der entstehen kann und um 
wie viele Kommastellen (10´er Potenzen) man zu groß ist, kann man die 
Zahl manuell in einem Schleifen-basierten Ansatz manuell zerlegen.

Das kann man mit 1-If + 8 If-else und einem else machen, oder 
laufzeiteffizienter nach dem Teile-Und-Herrsche Ansatz.

>Vielleicht kann ChatGpt etwas brauchbares oder wenigstens eine Idee erzeugen mit 
etwas wie

"Schreibe eine Schleife, welche eine 16 bit unsigned integer zahl in 
ihre einzelne Ziffern zerlegt und die einzelnen Ziffern in einem Array 
von char typen speichert"

von Norbert (der_norbert)


Lesenswert?

Jasson J. schrieb:
> Wenn das Ganze auf einer Platform ohne Floating-Point-Unit läuft, wäre
> folgender Ansatz effizienter mit Blick auf die Laufzeit

Das stimmt. Wenn man bedenkt das eine FP-Div zB. bei einem AVR maximal 
500 Taktzyklen braucht, könnte man bei einhundert Berechnungen pro 
Sekunde und 16MHz locker:
1
100 × 500 ÷ 16000000 =  0,003125
0.3% einsparen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Jasson J. schrieb:
> Den Faktor, der bei 3.3 / 256 herauskommt
... ist hier völlig uninteressant, weil das Ziel ja eine Prozentzahl des 
ADC-Werts ist.

> Den Faktor, der bei 3.3 / 256 herauskommt mit der 10´er Potenz
> multiplizieren, dass der Faktor keine Nachkommastelle mehr hat
Das hast du aber nicht auch mal nachgerechnet? Denn 3,3/256 ist 
0,012890625. Denn nach deiner Vorgehensweise müsste man also mit 
1000000000 multiplizieren. Da bräuchte dieser Faktor allein schon 26 
Bits.

Vor solcher umständlicher und unverständlicher Software graut mir. Wie 
die Rechnung ganz einfach mit einer Multiplikation und ganz ohne 
Division von vorne weg mit reinen 16-Bit Integerzahlen geht, habe ich 
schon gezeigt.

Norbert schrieb:
> könnte man ... 0.3% einsparen.
Auch wenn das sicher ein wenig sarkastisch gemeint ist: wenn man das 
eben nicht beachtet und sich die Denkweise "wird schon schnell genug 
sein" zu eigen macht, dann geht einem eben trotzdem mal die Rechenzeit 
aus...

: Bearbeitet durch Moderator
von Norbert (der_norbert)


Lesenswert?

Lothar M. schrieb:
> Auch wenn das sicher ein wenig sarkastisch gemeint ist:

War es…

> wenn man das
> eben nicht beachtet und sich die Denkweise "wird schon schnell genug
> sein" zu eigen macht, dann geht einem eben trotzdem mal die Rechenzeit
> aus...

Ich gebe zu, dass ich des Öfteren den Fehler begehe davon auszugehen, 
dass man sich bei der Software-Entwicklung im Allgemeinen und der 
µC-Entwicklung im Speziellen vorher Gedanken macht. ;-)

Daher ist der Einwand natürlich berechtigt.

von Flunder (flunder)


Lesenswert?

Rolf schrieb:
> Nein. In Programmiersprachen hängt die Art der Division oft vom Typ der
> Variablen ab:

Und in C meint das : vom Typ der Ausgangswerte/-variablen. Wo man das 
Ergebnis rein lädt ist dem Compiler erstmal schnuppe. Das macht erst was 
aus, wenn das konkrete Ergebnis nicht rein passt.

So wie der Versuch in eine so
1
static unsigned char percent = 0;
angelegte Variable eine 428 rein zu quetschen auf sehr vielen Systemen 
schief gehen dürfte. char muss IMHO mindestens nur 8 Bit haben und hat 
auf allem was nicht UTF16 oder UTF32 für Zeichen verwendet vermultich 
auch nicht mehr.

von Rainer W. (rawi)


Lesenswert?

Jasson J. schrieb:
> Den Faktor, der bei 3.3 / 256 herauskommt mit der 10´er Potenz
> multiplizieren, dass der Faktor keine Nachkommastelle mehr hat.

Das wird dir nicht gelingen.

Normalerweise reicht es, wenn der Restfehler bei der Skalierung 
insgesamt deutlich kleiner als 1/2 LSB ist. Dann geht er in den 
Wandlerfehlern unter.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Rainer W. schrieb:
> Das wird dir nicht gelingen.
Ich konnte das, denn es geht hier nicht darum, den endlosen Bruch 10/3 
zu erweitern, sondern lediglich um die Division 33/2560, die dann halt 
wie oben vorgerechnet 9 Nachkommastellen hat.

von Rainer W. (rawi)


Lesenswert?

Lothar M. schrieb:
> ... die dann halt wie oben vorgerechnet 9 Nachkommastellen hat.

Das ist völlig übertrieben. Es ist sinnlos, wesentlich genauer zu 
rechnen als die Genauigkeit der Eingangsdaten her gibt.
Auch hier gilt: Garbage in, Garbage out.
Wenn der Wandler 8 Bit hat, sind 4 gültige Stellen deutlich genug.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Rainer W. schrieb:
> Es ist sinnlos
Das ist mir durchaus klar. Natürlich würde ich in so einem Fall auch 
nur so weit gehen, dass nicht auf 12890625 erweitert wird, sondern nur 
bis 1289, weil der Rest dann nur noch 1/5 LSB sein kann.

Aber wie wiederholt gesagt: hier ist der ganze Rechenweg über die 3,3 
völlig sinnlos.

: Bearbeitet durch Moderator
von Rolf (rolf22)


Lesenswert?

Flunder schrieb:
> In Programmiersprachen hängt die Art der Division oft vom Typ der
>> Variablen ab:
>
> Und in C meint das : vom Typ der Ausgangswerte/-variablen. Wo man das
> Ergebnis rein lädt ist dem Compiler erstmal schnuppe.

Oh nein. Ein C-Compiler berücksichtigt IMMER den Typ der 
Ergebnisvariable. 
https://www.tutorialspoint.com/what-are-implicit-and-explicit-type-conversions-in-c-language

Angenommen, das Ergebnis hat – mathematisch gesehen –  den Wert 35. Wenn 
die Ergebnisvariable vom Typ uint8 ist, generiert er einen Code, der 8 
Bit abspeichert. Ist die Ergebnisvariable vom Typ float, dann generiert 
er einen Code, der 32 Bit abspeichert.

von Falk B. (falk)


Lesenswert?


von Rolf M. (rmagnus)


Lesenswert?

Rolf schrieb:
> Flunder schrieb:
>> In Programmiersprachen hängt die Art der Division oft vom Typ der
>>> Variablen ab:
>>
>> Und in C meint das : vom Typ der Ausgangswerte/-variablen. Wo man das
>> Ergebnis rein lädt ist dem Compiler erstmal schnuppe.
>
> Oh nein. Ein C-Compiler berücksichtigt IMMER den Typ der
> Ergebnisvariable.

Nein. Der Typ, mit dem eine Rechenoperation durchgeführt wird (und damit 
auch der Typ des Ergebnisses), hängt immer nur von den Operanden ab, 
niemals von dem Typ, wo der Ergebniswert im Anschluss reingeschrieben 
wird. Erst nach der Rechenoperation wird der Wert vom Ergebnistyp in den 
Zieltyp konvertiert.

> Angenommen, das Ergebnis hat – mathematisch gesehen –  den Wert 35. Wenn
> die Ergebnisvariable vom Typ uint8 ist, generiert er einen Code, der 8
> Bit abspeichert.

Nein. Der kleinste Typ, mit dem Rechenoperationen durchgeführt werden, 
ist int. Das nennt sich "integer promotion". Natürlich kann es 
passieren, dass der Optimizer hier Vereinfachungen vornimmt, aber diese 
dürfen das Ergebnis nicht mehr verändern. Es muss das gleiche 
rauskommen, als wäre die Berechnung mit Typ int durchgeführt worden.

> Ist die Ergebnisvariable vom Typ float, dann generiert
> er einen Code, der 32 Bit abspeichert.

Nein, er berechnet erst ein Ergebnis vom Typ int, danach wird dieser 
Wert dann nach float konvertiert.

Beispiel: Angenommen, wir haben eine Plattform, wo int 16 Bit breit ist.
1
unsigned int a = 50000;
2
unsigned int b = 50000;
3
unsigned long result = a + b;
In result steht nachher nicht etwa 100000, sondern 34464, denn die 
Berechnung wird mit Typ unsigned int durchgeführt, der bei 65536 
überläuft. Dass das Ergebnis nachher in eine long-Variable gespeichert 
wird, die genug Platz hätte, spielt keine Rolle. Die Berechnung wird 
äquivalent zu
1
unsigned int a = 50000;
2
unsigned int b = 50000;
3
unsigned int c = a + b;
4
unsigned long result = c;
durchgeführt.

: Bearbeitet durch User
von Michi S. (mista_s)


Lesenswert?

Rolf schrieb:
> Oh nein. Ein C-Compiler berücksichtigt IMMER den Typ der
> Ergebnisvariable.

Nein, das tut er eben nicht!
1
float f = 3/2;

liefert Dir in f 1.0 und nicht 1.5.

Ebenso wie Dich
1
longint l = 2000 * 2000;
eben nicht zum Millionär macht sondern magere 2304 in l ablegt.

Dagegen funktioniert
1
int i = 100 * 100;
wie erwartet; i wird auf 10000 gesetzt, aber das ist eine ganz andere 
Geschichte mit dem Titel Integer-Promotion. Denn alle Operanden deren 
Typ kleiner als int ist, werden als erstes mal nach int gewandelt und 
der größte der Operanden bestimmt dann den Typ des Ergebnisses.

von Rolf M. (rmagnus)


Lesenswert?

Michi S. schrieb:
> Ebenso wie Dich
> longint l = 2000 * 2000;
> eben nicht zum Millionär macht sondern magere 2304 in l ablegt.

Obacht: Das Überlaufverhalten vorzeichenbehafteter Typen ist 
undefiniert.

> Dagegen funktioniert
> int i = 100 * 100;
> wie erwartet; i wird auf 10000 gesetzt, aber das ist eine ganz andere
> Geschichte mit dem Titel Integer-Promotion. Denn alle Operanden deren
> Typ kleiner als int ist, werden als erstes mal nach int gewandelt und
> der größte der Operanden bestimmt dann den Typ des Ergebnisses.

Das passiert hier aber gar nicht, denn 100 ist sowieso schon vom Typ 
int.

von Rolf (rolf22)


Lesenswert?

Rolf M. schrieb:
>> Oh nein. Ein C-Compiler berücksichtigt IMMER den Typ der
>> Ergebnisvariable.
>
> Nein.

Es ging um das am Ende aus Programmierersicht abgespeicherte Ergebnis. 
Ich zitiere: "Wo man das Ergebnis rein lädt ist dem Compiler erstmal 
schnuppe."

float A;
A = 3/2; // liefert 1.0, abgespeichert werden 32 Bit

uint8 A1;
A1 = 3/2; // liefert 1, abgespeichert werden (zumindest bei einem 
8-Bit-µP) 8 Bit

Hat der Compiler nun den Typ von A bzw. A1 berücksichtigt oder nicht?
Würde er ihn nicht berücksichtigen, dann würde er im ersten Fall Müll in 
A abspeichern.

> Der kleinste Typ, mit dem Rechenoperationen durchgeführt werden,
> ist int. Das nennt sich "integer promotion".

Richtig. Aber das gilt nicht für das Abspeichern der Ergebnisse. Eine 
Variable vom Typ uint8 belegt im RAM je nach CPU nur 8 Bit. Aus 
Optimierungsgründen auch mal 16 Bit oder wieviel Bit auch immer der Typ 
int hat.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Rolf schrieb:
> Es ging um das am Ende aus Programmierersicht abgespeicherte Ergebnis.
> Ich zitiere: "Wo man das Ergebnis rein lädt ist dem Compiler erstmal
> schnuppe."

Mit "erstmal" ist hier die Berechnung gemeint, und für die ist der Typ 
tatsächlich Schnuppe.

> float A;
> A = 3/2; // liefert 1.0, abgespeichert werden 32 Bit

Da sind zwei komplett getrennte Operationen im Spiel:

- 3/2 liefert ein temporäres Objekt vom Typ int mit dem Wert 1
- A = 1 konvertiert diese 1 in einen float und schreibt den nach A.

> uint8 A1;
> A1 = 3/2; // liefert 1, abgespeichert werden (zumindest bei einem
> 8-Bit-µP) 8 Bit

Äquivalent zu oben:
- 3/2 liefert einen int mit dem Wert 1
- A1 = 1 kopiert den Wert nach A1 und konvertiert ihn dazu nach uint8

> Hat der Compiler nun den Typ von A bzw. A1 berücksichtigt oder nicht?

Bei der Berechnung hat er ihn nicht berücksichtigt. Bei der 
anschließenden Konvertierung in den Zieltyp wird der Zieltyp 
selbstverständlich berücksichtigt. Wie sollte diese Konvertierung denn 
auch sonst funktionieren?

>> Der kleinste Typ, mit dem Rechenoperationen durchgeführt werden,
>> ist int. Das nennt sich "integer promotion".
>
> Richtig. Aber das gilt nicht für das Abspeichern der Ergebnisse.

Das Abspeichern des Ergebnisses kommt wie gesagt nach der Berechnung. 
Erst wird mit int gerechnet, dabei entsprechend ein int produziert, 
später dann konvertiert.

> Eine Variable vom Typ uint8 belegt im RAM je nach CPU nur 8 Bit.

Wenn du uint8_t meinst, belegt der immer nur 8 Bit.

> Aus Optimierungsgründen auch mal 16 Bit oder wieviel Bit auch immer der
> Typ int hat.

Nein, das ist nicht erlaubt. uint8_t muss exakt 8 Bit breit sein.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.