Forum: Compiler & IDEs Typkonvertierung oder was?


von newbie12 (Gast)


Lesenswert?

Hallo Forumsleser,

ich programmiere schon seit einiger Zeit in C, bin aber nicht der Crack 
und bin nun einem Programmierproblem auf der Spur.

gegeben sei folgendes Beispiel:

byte GanzzahligerWert;

GanzzahligerWert = 100/(1+a/b);


wobei a und b Werte zwischen 1 und 50 annehmen kann. Ich vermute, dass 
zunächst der Klammerausdruck berechnet wird. Im Falle von a=1 und b=50 
wären das

GanzzahligerWert = 100/(1+1/50);


Kann es sein, dass der Klammerausdruck als Integer berechet wird und 
deshalb (1+1/50)=1 ist und deshalb

GanzzahligerWert = 100/(1+1/50);

den Wert von 100 und nicht wie im Taschenrechner 98 hat?

Ich habe ein bißchen recherchiert, bin aber auf keine klare Bezeichnung 
des Verhaltens gestoßen: implizite Typkonvertierung? Wie nennt sich das?


Besten Dank für Feedback
newbie12

von Max H. (hartl192)


Lesenswert?

newbie12 schrieb:
> Kann es sein, dass der Klammerausdruck als Integer berechet wird und
> deshalb (1+1/50)=1 ist
Ja, welche Datentypen habe a und b? Wenn es keine float/double sind, 
führt der Compiler automatisch eine Ganzzahl Division aus. Wenn es 
Integer sind, kannst du einen der beiden nach float/double casten um den 
Compiler zu einer fließkomma Division zu zwingen.

: Bearbeitet durch User
von newbie12 (Gast)


Lesenswert?

Hi
Sorry hatte ich vergessen a und b sind ebenfalls byte.
Newbie12

von Max H. (hartl192)


Lesenswert?

newbie12 schrieb:
> Sorry hatte ich vergessen a und b sind ebenfalls byte.
Ich vermute mal dass das eine 8bit breite Ganzzahl ist, dann würde es 
das beschriebene Verhalten erklären.

von newbie12 (Gast)


Lesenswert?

Max H. schrieb:
> newbie12 schrieb:
>> Sorry hatte ich vergessen a und b sind ebenfalls byte.
> Ich vermute mal dass das eine 8bit breite Ganzzahl ist, dann würde es
> das beschriebene Verhalten erklären.

..ja, genau, byte hat einen Wertebereich von 0..255.

newbie12

von Sebastian V. (sebi_s)


Lesenswert?

Alternativ könntest du b*100/(a+b) rechnen. Dann gibts die Division erst 
ganz am Ende und es kommt zumindest irgendwas anderes als 100 raus. Bei 
deinem Beispiel mit a = 1 und b = 50 kommt bei mir auch nicht 98 raus 
sondern 98.03921569...
Wenn du es als b*100/(a+b) hinschreibst kriegst du immer den 
abgerunderen ganzzahligen Wert den der Taschenrechner anzeigt 
(angenommen die Zwischenergebnisse werden nicht zu groß für int).

: Bearbeitet durch User
von ffff (Gast)


Lesenswert?

empfehlung: lies ein gutes Buch oder ein gutes Online-Tutorial und 
arbeite solche Dingen durch. Wenn man in C programmieren will, dann 
sollte man wissen was implizit hinter jeder Operation passiert.

Dann treten genau solche einfachen und leicht zu vermeidbaren Fehler 
überhaupt nicht auf.

von Sebastian V. (sebi_s)


Lesenswert?

newbie12 schrieb:
> Ich habe ein bißchen recherchiert, bin aber auf keine klare Bezeichnung
> des Verhaltens gestoßen: implizite Typkonvertierung? Wie nennt sich das?

Das nennt sich Rechnen mit Ganzzahlen. Es wird dort gar nichts 
konvertiert (außer vielleicht Integer Promotion weil du sagtest, dass du 
mit Bytes rechntest. Wenn du mit Werten kleiner als int rechnest wird 
das implizit zu einem int hochkonvertiert). Implizite Konvertierung gibt 
es wenn die Operanden unterschiedliche Typen haben. Also z.B. ein float 
und ein int. Dann wird implizit zu einem float konvertiert und man kann 
einfach sowas wie 1.f/a schreiben wenn a ein int ist.

: Bearbeitet durch User
von newbie12 (Gast)


Lesenswert?

ffff schrieb:
> empfehlung: lies ein gutes Buch oder ein gutes Online-Tutorial und
> arbeite solche Dingen durch. Wenn man in C programmieren will, dann
> sollte man wissen was implizit hinter jeder Operation passiert.
>
> Dann treten genau solche einfachen und leicht zu vermeidbaren Fehler
> überhaupt nicht auf.

@all: Danke erstmal an alle für die Überlegungen.

@ Sebastian V. O.: Das mit dem Umformen habe ich auch gemacht. 
Tatsächlich ändert sich das Ergebnis, wenn ich es so umforme, wie du 
vorgeschlagen hast.

@ffff: So ein C-Tutorial/Buch ist groß. Ziel meiner Frage war, das 
beschriebene Verhalten einer Begrifflichkeit zuzuordnen, die man im 
Tutorial gezielt suchen kann. Es geht um die Reihenfolge der Abarbeitung 
eine Kette von arithmetischen Operationen bei gleichzeitiger 
Beschränkung des Wertebereiches.

 Sebastian V. O. hat es gut herausgearbeitet:

GanzzahligerWert = 100/(1+a/b) und

GanzzahligerWert = 100*b/(b+a)

führen zu verschiedenen Ergebnissen. Vermutlich ist es so einfach, wie 
Sebastian V. O. es bereits gesagt hat: "Das nennt sich Rechnen mit 
Ganzzahlen". Ich vermute mal, dass das für jeden (längeren) 
arithmetischen Ausdruck gilt: jeder Wert, der sich aus zwei Operanden 
und einem Operator ergibt, hat den gleichen Wertebereich, wie die 
Variable, der am Schluß zugewiesen wird.

Ich habe verstanden. Hoffentlich auch mein Compiler.

Dank und guten Abend
newbie12

von Sebastian V. (sebi_s)


Lesenswert?

newbie12 schrieb:
> Ich vermute mal, dass das für jeden (längeren)
> arithmetischen Ausdruck gilt: jeder Wert, der sich aus zwei Operanden
> und einem Operator ergibt, hat den gleichen Wertebereich, wie die
> Variable, der am Schluß zugewiesen wird.

Nein der Typ aus zwei Operanden mit Operator ergibt sich aus den Typen 
der Operanden. Wenn die Typen unterschiedlich sind wird der Typ mit dem 
"größeren" Wertebereich gewählt. Also bei einem int und long ist der 
neue Typ ein long. Bei int und float gibts einen float. Wenn der 
arithmetische Ausdruck fertig berechnet ist gibts noch eine implizite 
Konvertierung zu dem Typ der Variable, welchem der Wert zugewiesen wird.

Das hier sieht nach einer einigermaßen ausführlichen Beschreibung aus: 
http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/007_c_typumwandlung_001.htm

: Bearbeitet durch User
von newbie12 (Gast)


Lesenswert?

Sebastian V. O. schrieb:
> newbie12 schrieb:
>> Ich vermute mal, dass das für jeden (längeren)
>> arithmetischen Ausdruck gilt: jeder Wert, der sich aus zwei Operanden
>> und einem Operator ergibt, hat den gleichen Wertebereich, wie die
>> Variable, der am Schluß zugewiesen wird.
>
> Nein der Typ aus zwei Operanden mit Operator ergibt sich aus den Typen
> der Operanden. Wenn die Typen unterschiedlich sind wird der Typ mit dem
> "größeren" Wertebereich gewählt. Also bei einem int und long ist der
> neue Typ ein long. Bei int und float gibts einen float. Wenn der
> arithmetische Ausdruck fertig berechnet ist gibts noch eine implizite
> Konvertierung zu dem Typ der Variable, welchem der Wert zugewiesen wird.
>
> Das hier sieht nach einer einigermaßen ausführlichen Beschreibung aus:
> http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/007_c_typumwandlung_001.htm

besten Dank, auch für den Buchtipp und die Kategorie "Typumwandlung".

Newbie12

von Dirk B. (dirkb2)


Lesenswert?

newbie12 schrieb:
> hat den gleichen Wertebereich, wie die
> Variable, der am Schluß zugewiesen wird.

Nein.

Das ist ein beliebter Fehler, der oft für Verwrrung sorgt.
Dafür ist nur die rechte Seite vom = wichtig.

Bei der Berechnung gelten die normalen Regeln wie Klammerung, Punkt vor 
Strich, ...
Und es wird nur die für die jeweilige Operation notwendige Umwandlung 
gemacht.

Bei 1.5 + 1/2 kommt 1.5 raus (double), da erstmal 1/2 als Integerdivison 
berechnet wird.

von python (Gast)


Lesenswert?

python2 rechnet ganzzahl wenn keine floats drinne
python3 rechnet einfach so float wenn er meint es muss sein

total verwirrend und absolut off topic :)

von Rosa (Gast)


Lesenswert?

>empfehlung: lies ein gutes Buch oder ein gutes Online-Tutorial und
>arbeite solche Dingen durch. Wenn man in C programmieren will, dann
>sollte man wissen was implizit hinter jeder Operation passiert.

>Dann treten genau solche einfachen und leicht zu vermeidbaren Fehler
>überhaupt nicht auf.

Super konstruktiver Vorschlag. In der Zeit hättest Du die Lösung 
präsentieren können :-(

Warum nimmst Du nicht float als Datentyp für a und b?
Rosa

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rosa schrieb:
> Super konstruktiver Vorschlag.

Der Vorschlag ist konstruktiv. Selbst lernen. Nicht eine Antwort 
vorbeten lassen, ohne zu verstehen.

Aber das ist in der Generation facebook/google offensichtlich nicht zu 
vermitteln.

> Warum nimmst Du nicht float als Datentyp für a und b?

Versuch mal darüber nachzudenken, was das bedeutet. Wie heißt diese 
Webseite hier? "mikrocontroller.net".

Und welche Auswirkung kann die Verwendung von float auf einem 
Mikrocontroller haben? Na?

von Kaila (Gast)


Lesenswert?

Es ist doch auch eine Frage, ob auf Seiten der Anwendung etwas dagegen 
spricht. Mehr habe ich nicht gefragt.
Ich glaube, du hast meine Antwort persönlich genommen. Entschuldige 
bitte, das kommt nicht wieder vor.

Rosa

Ps: ich glaube schon zu wissen, was es bedeutet, float zu nutzen.
Pps:Vorführen und Nachmachen ist nicht mal die schechteste Methode, 
schlechter ist ein Buch, das ich nicht verstehe.

von Kaila (Gast)


Lesenswert?

Aber einen kann ich mir jetzt nicht verkneifen:
Rufus T. Firefly! Der Name ist der Hammer. Was bedeuttet das T?

Take it easy :-)
Rosa

von Yalu X. (yalu) (Moderator)


Lesenswert?

python schrieb:
> python2 rechnet ganzzahl wenn keine floats drinne
> python3 rechnet einfach so float wenn er meint es muss sein
>
> total verwirrend und absolut off topic :)

Verwirrend in Python 2 ist wie auch in C vor allem die Tatsache, dass
der /-Operator je nach Argumenttypen für zwei völlig unterschiedliche
Operationen steht. Denn die ganzzahlige Division ist im mathematischen
Sinn gar keine Division, da sie nicht als Umkehrung der Multiplikation
definiert ist.

Während in C diese Dimorphie lediglich ein Stolperstein für Anfänger
darstellt, ist sie in Python 2 eine generelle Fehlerquelle. Deswegen
liefert / in Python 3 auch für Integer-Argumente ein Float-Ergebnis mit
den entsprechenden Nachkommastellen. Für die ganzzahlige Division gibt
es den Operator //.

Evtl. wäre es auch bei der Sprachdefinition von C klüger gewesen, zwei
verschiedene Operatoren für die beiden Divisionsarten vorzusehen.

Womit wir auch schon fast wieder ontopic wären ;-)

von Arc N. (arc)


Lesenswert?

Yalu X. schrieb:
> Evtl. wäre es auch bei der Sprachdefinition von C klüger gewesen, zwei
> verschiedene Operatoren für die beiden Divisionsarten vorzusehen.
>
> Womit wir auch schon fast wieder ontopic wären ;-)

Und noch etwas mehr Off-Topic:
Da würden Mathematiker wohl etwas dagegen haben...
Das, was C da macht, ist ganz normale Arithmetik über einem 
Restklassenring bzw. Faktorring und hat den schönen Nebeneffekt, dass 
bspw., falls das multiplikate Inverse existiert, eine Division durch 
eine Multiplikation mit dem Inversen berechnet werden kann.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Arc Net schrieb:
> Da würden Mathematiker wohl etwas dagegen haben...

Ich bin zwar selber kein Mathematiker, könnte mir aber vorstellen, dass
gerade Mathematiker eine klarere Unterscheidung zwischen der echten und
der ganzzahligen Division befürworten würden.

Gerade in den funktionalen Programmiersprachen, die prinzipiell etwas
mathematischer angehaucht sind als andere, wird diese Unterscheidung
praktisch immer gepflegt.

> Das, was C da macht, ist ganz normale Arithmetik über einem
> Restklassenring bzw. Faktorring und hat den schönen Nebeneffekt, dass
> bspw., falls das multiplikate Inverse existiert, eine Division durch
> eine Multiplikation mit dem Inversen berechnet werden kann.

Solche Späße wären aber doch auch möglich, wenn der Operator für die
ganzzahlige Division ander als / heißen würde, oder?

von Py3 (Gast)


Lesenswert?

python schrieb:
> python3 rechnet einfach so float wenn er meint es muss sein

Was natürlich Unsinn ist.

Python 3 ist sehr viel konsistenter als Python 2, was das 
Divisionsverhalten angeht. Siehe / vs. //

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.