uint16_t Subtraktion mit uint32_t

Gast #6928318
Lesenswert?

Hallo,

ich habe da in meinem Programm-Code etwas interessantes festgestellt, 
dass ich gerade nicht nachvollziehen kann:

Wenn ich von einer uint16_t Variable mit dem Wert z.B. 700, den Wert 
einer uint32_t Variable mit dem Wert 4294967295 abziehe, dann erhalte 
ich 699.
1
uint16_t x = 700;
2
uint32_t y = 4294967295;
3
x = x - y;
4
// x = 699

Das ist für mich gerade auch so passend, aber wieso wird dabei immer 
genau -1 abgezogen? Ich habe versucht dies mit binärer Subtraktion 
nachzuvollziehen, aber ganz verstehe ich es irgendwie nicht.

Danke für jeden Hinweis
Gast #6928320
Lesenswert?

hawky schrieb:
> aber wieso wird dabei immer genau -1 abgezogen?

Deine Zahl ist nicht zufällig, sondern 2^32-1 = 0xffffffff-1 = 
4294967296-1

Es ist unwahrscheinlich, dass 1 abgezogen wird und 699 rauskommt. Eher 
wird (wie Du schriebst) -1 abgezogen und es kommt 701 raus.

Tu Dir den Gefallen und spiele das mit uint8 und uint16 durch, die Zahl 
dazu heisst 65535 (oder 0xffff)
(Firma: egal) #6928337
Lesenswert?

A. S. schrieb:
> Deine Zahl ist nicht zufällig, sondern 2^32-1 = 0xffffffff-1 =
> 4294967296-1

Fast, aber nicht ganz:
- 4294967295 = 0xFFFFFFFF = 2^32 - 1
- 2^32 = 4294967296 = 0x100000000

Das mit Problem dürfte eher mal wieder folgendes sein:
1
- (uint16_t)x = (int)x - (int)y;
Und "unsigned 0xFFFFFFFF" entspricht hierbei "singend -1" wenn es sich 
bei "int" um einen 32Bit Wert handelt
Gast #6928349
Lesenswert?

Irgend W. schrieb:
> Und "unsigned 0xFFFFFFFF" entspricht hierbei "singend -1" wenn es sich



(prx) A. K. schrieb:
> uint32_t wird nicht in int gerechnet, es sei denn int hätte mehr
> als 32
> Bits. Das ist aber auf keiner gängigen Plattform der Fall.

also diese uint32_t y variable wird irgendwo in meinem Code auch 
dekrementiert, und 0 - 1 ergibt dann halt den überlauf bzw. diese 
0xFFFFFFFF.

hmm ok, aber irgendwie verstehe ich es trotzdem noch nicht ganz, wieso 
wird mit signed gerechnet?
Beitrag #6928351 wurde von einem Moderator gelöscht.
#6928361
Lesenswert?

Mombert H. schrieb:
> hawky schrieb:
>> hmm ok, aber irgendwie verstehe ich es trotzdem noch nicht ganz, wieso
>> wird mit signed gerechnet?
>
> Wie A. K. schon gesagt, wird nicht in signed gerechnet. Du solltest, wie
> einige andere hier im Thread ein gutes C-Buch lesen. Dort sollte so
> etwas wie "usual arithmetic conversions" auftauchen, wo das erklärt
> wird.

Hier ist kein C Buch gefragt, sondern Basis-Ganzzahl-Arithmetik - 
insbesondere Modulo (bei uns als Division mit Rest bekannt) 
Arithmentik...

Die Addition von einer uint Zahl wo alle Bits gesetzt sind, entsprich 
faktisch einer Subtraktion von 1 in solch einer Zahlengeraden.

Fun fact: Intern kann ein AVR nur konstanten von variablen subtrahieren, 
nicht addieren (nur zwei variablen - register - können miteinander 
addiert werden). Wenn man also i++ oder i-- schreibt, wird das vom 
compiler in den gleichen Befehl umgesetzt SUBI i, -1 im ersten Fall - in 
hex: SUBI i, 0xFF. Und im zweiten Fall SUBI i, 1 bzw SUBI i, 0x01.
Gast #6928375
Lesenswert?

Stell dir vor nach jeder Rechenoperation rechnest du "mod 4". Nimm eine 
Zahl und addiere 3. Jetzt hast du eins weniger als die zahl. Jetzt 
stelle dir vor, du rechnest erst mod 8, dann mod 4. Nichts ändert sich.
Das ist weil 8 ein vielfaches von 4 ist. Mit 8 mod 2 geht's halt exakt 
2mal im kreis rum. Ist im Grunde das selbe hier, nur mit etwas grösserem 
Wertebereich.
Gast #6928517
Lesenswert?

hawky schrieb:
> ach sorry ja, also ganz korrekt schaut es so aus:
> uint16_t x = 700;
> uint32_t y = 4294967295;
> x = x + y;
> // x = 699

Ja. Wie mehrfach beschrieben. Und jetzt zieh das Beispiel auf 8/16 oder 
8/8 bit und

hawky schrieb:
> versucht dies mit binärer Subtraktion nachzuvollziehen,
1
uint8_t x = 7;
2
uint8_t y = 255;
3
x = x + y;
4
// x = 6
#6928535
Lesenswert?

EAF schrieb:
> int kann auch 64 Bit breit sein, dann passt das schon

Ist aber selten, in Windows und Linux ist "int" 32 Bits breit:
https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models

Sollte man natürlich trotzdem fürs Verständnis der Sprache im Auge 
behalten, oder um sich von vorneherein portable Programmierung 
anzugewöhnen.
#6928560
Lesenswert?

unsigned schrieb:
> Im Prinzip hat man schon hier ein Problem. Die zugewiesene Zahl ist vom
> Typ int, aber der Wert passt da gar nicht rein.

Eine dezimal geschriebene Zahl ist vom kleinsten Typ, in den sie 
passt, in der Reihenfolge int => long => long long. Zahlen auf anderer 
Basis, wie etwa Hex, haben eine andere Reihenfolge.

Da die Zahl 4294967295 in "int" nicht reinpasst, ist sie je nach 
Plattform eben nicht vom Typ "int", sondern auch ohne Suffix automatisch 
vom Typ "long" oder "long long".
#6928618
Lesenswert?

Richard S. schrieb:
> Mombert H. schrieb:
>> hawky schrieb:
>>> hmm ok, aber irgendwie verstehe ich es trotzdem noch nicht ganz, wieso
>>> wird mit signed gerechnet?
>>
>> Wie A. K. schon gesagt, wird nicht in signed gerechnet. Du solltest, wie
>> einige andere hier im Thread ein gutes C-Buch lesen. Dort sollte so
>> etwas wie "usual arithmetic conversions" auftauchen, wo das erklärt
>> wird.
>
> Hier ist kein C Buch gefragt, sondern Basis-Ganzzahl-Arithmetik -
> insbesondere Modulo (bei uns als Division mit Rest bekannt)
> Arithmentik...
Natürlich ist hier Ganzzahl-Arithmetik gefragt, nur was genau? Hat sich 
Irgend W. (Firma: egal) (irgendwer) nur verrechnet, oder hat er etwas 
falsches gerechnet? Hat sich der TO nur verrechnet, oder hat er nicht 
verstanden was er rechnen muss?

> Die Addition von einer uint Zahl wo alle Bits gesetzt sind, entsprich
> faktisch einer Subtraktion von 1 in solch einer Zahlengeraden.
Bis auf all die Fälle, wo es etwas anderes bedeutet.
Gast #6928669
Lesenswert?

Mombert H. schrieb:
> Hat sich Irgend W. (Firma: egal) (irgendwer) nur verrechnet, oder hat er
> etwas falsches gerechnet?
Er hat gar nichts gerechnet


> Hat sich der TO nur verrechnet, oder hat er
> nicht verstanden was er rechnen muss?

Er hat zwar + und - verwechselt, ansonsten aber nichts zu seinem Problem 
geschrieben. Also was er erwartet hätte oder wie er gerechnet hat, ob er 
den Überlauf bei unsigned kennt oder ob sich seine Frage erledigt hat, 
wenn er + statt - rechnet..
#6928764
Lesenswert?

Das Problem lässt sich ja auch mit dezimalen Zahlen bewerkstelligen, 
welche eine begrenzte Stellenzahl haben.

Maximal vierstellig darstellbare Zahl = 9999

Nun soll von einer zweistelligen Zahl diese Zahl abgezogen werden:

39 - 9999 = -9960

Da wir aber keine negativen Zahlen darstellen, muss einaml der gesamte 
darstellbare Bereich (also die erste nicht mehr darstellbare Zahl) 
addiert werden - das passiert bei einem Überlauf von selbst:

-9960 + 10000 = 40


Oder nochmal anders:

Du hast einen 3-stelligen km Zähler.
Fährst Du 1000km, steht das selbe wie vorher auf dem Zähler.
Fährst Du 1000km rückwärts, ebenfalls.
Fährst Du nur 999km rückwärts, steht 1km mehr drauf als vorher.

Nun sollte man es aber begriffen haben ...

Gruß
Jobst

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren