32bit VAriable rollt bei 28bit über?

Hi,

ich habe gerade etwas herum gespielt und versucht eine Rechnung für die ich normalerweise float verwenden würde, auf einem Uno nur mit Integer zu lösen. (Hochrechnen von U2 auf Uges in einem Spannungsteiler)
Dabei liefert eine Teilrechnung ein falsches Ergebnis, bzw die Variable scheint über zu rollen. Ich versuche das mit dem Taschenrechner nachzuvollziehen, und für meine Begriffe kommt die Rechnung nicht über die Größe der Variablen hinaus.
Ich habe unsigned 32bit deklariert, und das Zwischenergebnis hat nur 28bit.
Ich stehe wahrscheinlich einfach total auf dem Schlauch. Kann mir jemand helfen meinen Fuß von der Leitung zu bekommen?

void setup() {
  Serial.begin(9600);
 uint16_t r1 = 150; //kohm
 uint16_t r2 = 47; //kohm
 uint16_t a =1023; //Beispielswert von analogRead(A0)

 uint16_t b;
  //b = a / ( r2 / ( r1 + r2)); Geht gar nicht, führt zu Division durch Null.
  b = a * (( r1 + r2) / r2); // man kann umstellen, aber die Rechnung bleibt sehr ungenau.  
  Serial.println(b);


  //Um drei Stelle verschoben für höhere Genauigkeit:
  uint32_t c;
  c = a * ((r1 + r2 )*1000); //Hier rollt der Wert scheinbar über, obwohl das Ergebnis doch nur 28bit hat.
  Serial.println(c);
  c = c / r2;
  Serial.println(c);
  c = c/1000;             
  Serial.println(c);  //Wird genauer, aber selbst 32bit können knapp werden.

  
  float d;
  d = (float)a / ( (float)r2 / ( (float)r1 + (float)r2)); //ist genau, aber float.
  Serial.println(d);
  d = (float)a / 0.23857868020304568528; // Zwischenergebnis gleich hart in den Code schreiben nimmt dem Arduino die Arbeit ab.
  Serial.println(d);
}

void loop(){}

Btw. Wie rechnet ihr sowas?

edit.
Ich bin selbst drauf gekommen. Ich muss jede einzelne 16bit Variable in der Rechnung auf 32bit casten. ...Und das merke ich nachdem ich Jahre lang 32bit und 16bit ohne cast wild miteinander verrechnet habe, ohne Probleme zu bekommen. Das ist dann wohl ein Fall von "Mehr Glück als Verstand." :smiley:

Dennoch bleibt die Frage, wie rechnet ihr sowas? Gibt es eine Möglich um float herum zu kommen, UND keine riesige Variable verwenden zu müssen?

Wenn Zwischenergebnisse mit int nicht ausreichend abgebildet werden können, dann musst Du entweder zu unsigned int wechseln oder zu unsigned long. Das kannst nur Du wissen, wie Deine Werte kommen können.
Ich würde aber immer erst die Multiplikation und dann die Division ausführen:

b = a * ( r1 + r2) / r2;

Weil Du dann eine größere Basis für die Division hast.

Gruß Tommy

c = a * ((r1 + r2 )*1000);
Da wird mit integer gerechnet.

c = a * ((r1 + r2 )*1000UL);
ist richtig.

https://forum.arduino.cc/index.php?topic=333318.0
Grüße Uwe

gsezz:
Ich muss jede einzelne 16bit Variable in der Rechnung auf 32bit casten

Nur eine der beiden Variablen in einer Operation muss 32 Bit sein. Die andere wird automatisch angepasst. Das läuft alles nach fest definierten Regeln ab.