Forum: Mikrocontroller und Digitale Elektronik Anfängerfrage Variablen Größe bei Berechnungen in C


von Thomas (Gast)


Lesenswert?

Hallo,
ich bin recht neu, was Programmierung angeht und hätte folgende Frage:

Als Beispiel habe ich mal eine Prozentrechnung ausgesucht. Dabei ist 
100% = 255 und als Ergebnis reicht mir eine Ganzzahl. Reicht es dann aus 
der Variable "Ergebnis" auch nur 8 Bit zuzuweisen? Der Zwischenschritt 
"Wert * Prozent" ist ja kurzzeitig größer als 255. Hier würde mich als 
Grundlagenfrage interessieren, wo so ein Zwischenschritt in der 
Berechnung gespeichert wird? Wäre es in der Variable, müsste ich ja die 
Variable entsprechend groß planen, um keine Speicherprobleme zu 
bekommen?
Mich interessiert einfach die Funktionsweise dahinter und ich möchte es 
natürlich gerne richtig machen und nicht unnötigerweise meine Variablen 
immer zu groß definieren. Für Google habe ich wohl nicht die richtigen 
Begriffe erwischt.
1
uint8_t Ergebnis;
2
uint8_t Wert;
3
uint8_t Prozent;
4
5
Prozent = 80;
6
Wert = 255;
7
8
Ergebnis = Wert * Prozent / 100;

von Kevin M. (arduinolover)


Lesenswert?

So wird das nicht funktionieren. Er wird zuerst 255*80 rechnen was zu 
groß ist und zu einem Überlauf führt und anschließend durch 100 teilen. 
Ich bin mir Grade nicht sicher ob es da ein definiertes verhalten gibt 
aber vermutlich bleibt er einfach bei 255 und teilt durch 100 oder tut 
irgend was anderes was du nicht möchtest. Alternative kannst du erst 
durch 100 teilen und dann mal 80 rechnen, hier wird die aber ordentlich 
Präzision verloren gehen, da er die 2,55 zu 2 macht. Meiner Meinung nach 
solltest du mit einem 16 Bit Wert rechnen und erst mit 80 multiplizieren 
und anschließend durch 100 teilen.

von foobar (Gast)


Lesenswert?

Datentypen kleiner als int gibt es nur im Speicher - sobald sie aus dem 
Speicher geholt werden, werden sie auf int-Größe erweitert.  Gerechnet 
wird also prinzipiell immer mit mindestens int-Größe.  Wie groß ein int 
ist, ist compilerabhängig - üblich sind 16 (bei z.B. AVR) und 32 Bit.

Das ist das, was der Compiler machen muß - der Optimizer reduziert das 
evtl wieder (zu z.B. 8-Bit-Arithmetik), wenn er garantieren kann, dass 
trotzdem das korrekte Ergebnis rauskommt.

von GeraldB (Gast)


Lesenswert?

Kann man das nicht evtl. sicherheitshalber casten?
1
Ergebnis = (uint8_t) Wert * Prozent / 100;

von Rolf M. (rmagnus)


Lesenswert?

GeraldB schrieb:
> Kann man das nicht evtl. sicherheitshalber casten?

Casten kann man das. Aber mit welchem Sinn?

foobar schrieb:
> Gerechnet wird also prinzipiell immer mit mindestens int-Größe.

Genau. Damit funktioniert die Rechnung, da int immer mindestens 16 Bit 
breit ist und der Maximalwert von 255 * 100 für das Zwischenergebnis da 
rein passt.

von Gerald K. (geku)


Lesenswert?

Eingabe 0 liefert 0x00, Eingabe >=100 liefert 0xff
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <inttypes.h>
5
6
int main(int argc, char* argv[])
7
{
8
   uint8_t Ergebnis;
9
   uint8_t Wert;
10
   uint8_t Prozent;
11
12
   Prozent =atoi(argv[1]);
13
   if (Prozent > 100) Prozent = 100;
14
   Wert = 255;
15
   Ergebnis =(uint8_t)((unsigned int)Wert * (unsigned int)Prozent / 100);
16
17
   printf("Prozent: %d Ergebnis: 0x%02x\r\n",Prozent,Ergebnis);
18
}

von A. S. (Gast)


Lesenswert?

Thomas schrieb:
> Für Google habe ich wohl nicht die richtigen Begriffe erwischt

Integer Promotion

von nicht so wichtig (Gast)


Lesenswert?

Gerald K. schrieb:
> Eingabe >=100 liefert 0xff

Nein, in der Zeile

Gerald K. schrieb:
> Prozent =atoi(argv[1]);

werden nur die letzten 8 Bits übernommen. Wenn man eine riesige Zahl 
eingibt (z.B.  0xAAAAAA01 bei 4Bytes-Int) wo die letzten 8 Bits eine 
Zahl <100 ergeben, dann wird falsch gerechnet (obwohl die eingegebene 
Prozentzahl riesig ist).

Da wird tatsächlich abgeschnittet.

von Gerald K. (geku)


Lesenswert?

nicht so wichtig schrieb:
> Da wird tatsächlich abgeschnittet.

Danke für den Hinweiß.

Man muss die Abfrage direkt auf das Ergebnis von atoi() machen.

von Bernd (Gast)


Lesenswert?

C wandelt beide Variablen in die größere der Variablen um und das 
Ergebnis besteht ebenfalls aus diesem Typ. Bei einem 8-Bit- und einem 
16-Bit-Wert werden der 8-Bit-Wert erst in 16 Bit umgewandelt und dann 
gerechnet und ein 16-Bit-Wert ausgegeben. Ebenso wird bei int und float 
erst in float umgewandelt, das Ergebnis ist dann auch float. Es würde 
also oben im Beispiel reichen, eine Variable zu casten. Es würde nicht 
reichen, die 100 auf 16 Bit zu casten, weil erst die Multiplikation 
ausgeführt wird. Es mag sein, das ein Compiler grundsätzlich in int 
rechnet, aber besser ist es trotzdem, explizit zu casten, dann weiß man, 
was man tut und der Code bleibt portierbar.

Bernd

von Rolf M. (rmagnus)


Lesenswert?

Bernd schrieb:
> C wandelt beide Variablen in die größere der Variablen um und das
> Ergebnis besteht ebenfalls aus diesem Typ.

Mindestens jedoch int. Das nennt sich in C-Sprech "integer promotion".

> Bei einem 8-Bit- und einem 16-Bit-Wert werden der 8-Bit-Wert erst in 16
> Bit umgewandelt und dann gerechnet und ein 16-Bit-Wert ausgegeben.

Nur wenn int 16 Bit breit ist. Wenn der 32 Bit breit ist, werden beide 
Seiten erst auf 32 Bit erweitert.

> Ebenso wird bei int und float erst in float umgewandelt, das Ergebnis ist
> dann auch float.

Die genauen Regeln können aber etwas komplizierter sein. Das findet man 
unter dem Begriff "usual arithmetic conversions".

> Es würde also oben im Beispiel reichen, eine Variable zu casten.

Es würde auch reichen, gar keine zu casten. Ich würde gerade einem 
Anfänger raten, nur dann einen Cast einzusetzen, wenn er auch notwendig 
ist und wenn man genau erklären kann, warum er notwendig ist.

> Es würde nicht reichen, die 100 auf 16 Bit zu casten,

100 ist vom Typ int und damit sowieso mindestens 16 Bit breit.

> Es mag sein, das ein Compiler grundsätzlich in int rechnet,

Jeder standardkonforme Compiler tut das.

: Bearbeitet durch User
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.