Rechnen und variablen

Hi,
ich steh mal wieder voll aufm schlauch, aber komme einfach nicht weiter.
Ich möchte gerne aus einem 12Bit Wert, der in einer unsigned long variable steht, einen prozentualen long Wert ausrechnen.
Verdeutlichung:
Wert zwischen 0 und 4095, z.B. 3877
Dieser Wert soll mit dem Ergebnis aus x/ 255, z.B. 245/255 multipliziert werden.
Also möchte ich 3877 * 245 / 255 rechnen.
Am Beispiel sieht ihr mein Problem, denn wenn x=255 ist, dann muss ja das Ergbnis 3877 ergeben.
3877 * 255 / 255 = 3877 *1 = 3877
Und da liegt mein Problem, egal welchen Variable Typ ich nehme, kommt immer nen gerundeter Wert raus:

void setup() {
  Serial.begin(19200);  
}

void loop() {
  int calc1 = 3877 / 255 * 255; //3825
  unsigned long calc2 = 3877 / 255 * 255; //3825
  float calc3 = 3877 / 255 * 255; //3825.00
  
  Serial.println(calc1);
  Serial.println(calc2);
  Serial.println(calc3);
  delay(1000);
}

Wenn ich die Reihenfolge umdrehe, also 3877 * 255 / 255, dann wirds noch übler. zumindest bei der long variable müsste das doch eigentlich funktionieren???

Klärt mich bitte auf

Ich behaupte, das ist falsch, da bei der Berechnung (rechts vom =) keine Fließkommazahl zum einsatz kommt.

float calc3 = 3877 / 255 * 255; //3825.00

Teste mal, eine der Zahlen als Fließkommazahl zu schreiben, 3877.00 oder aber....

float calc3 = (float)3877 / 255 * 255; //3825.00

Was kommt raus wenn Du float calc3 = 3877.0 / 255.0 * 255.0; schreibst?

zur lösung Deines Problems Teile den 12 Bit Wert einfach durch 4. um einen 8 bit wert zu erhalten.

ansonsten Verhältnisrechenug: 4095 zu 3877 wie 255 zu x. oder anders geschrieben; 4095:3877=255:x Auflösung nach x. x in diesem Fall Außengleid x= Innengleid mal Innenglied gebrochen Außengleid =3877*255/4095

Grüße Uwe

currymuetze: Wenn ich die Reihenfolge umdrehe, also 3877 * 255 / 255, dann wirds noch übler. zumindest bei der long variable müsste das doch eigentlich funktionieren

Dein Ergebnis ist long. Nicht die Zahlen mit denen du rechnest. Die sind per Default int. Und 3877 * 255 übersteigt den Wertebereich bei weitem. Der rechnet dann mit int und weist das Ergebnis einem long zu.

Dafür gibt es Integer-Konstanten/Literale: http://arduino.cc/en/Reference/IntegerConstants

Wenn du "long test = 3877L * 255;" machst wird auch in long gerechnet (oder UL für unsigned long). Das gleiche mit Float. Divisionen sind standard-mäßig ganzzahlig! Mindestens eine deiner Zahlen muss daher entweder Nachkommastellen haben oder auf float gecastet werden - wie oben beschrieben.

Hiermit klappts: float calc3 = (float)3877 / 255 * 255; //3825.00

Vielen Dank - manchmal probiert man sich echt nen wolf - gut dass man hier so schnell feedback bekommt. Schau mir die links morgen noch mal an. Für heute reichts

Bist du sicher, dass du nicht mit 4096 und 256 rechnen möchtest ?

Ansonsten ist das natürlich auch richtig:

** **if  (  (3877L * 255) / 255  == 3877L ) Serial.println ("Was sonst ?");** **

  unsigned long wert12bit = 3877;    // das hätte auch den Verzweiflungs-Umweg via float gespart
  unsigned long calc2 = wert12bit / 255 * 255;

Vergleiche von Float Variablen ist gefährlich. Durch Rundungsfehler sind die Zahlen leicht etwas verschieden und darum schlägt ein == Vergleich fehl. Grüße Uwe

Hallo,

Float Vergleich besser als Subtraktion beider zu vergleichender Werte - der Betrag der Subtraktion muss kleiner als 0,0000xxx sein, dann sind die Werte gleich.

Nur mal so als Ansatz...

Grüße, Jürgen

Vergleiche von Float Variablen ist gefährlich. Durch Rundungsfehler sind die Zahlen leicht etwas verschieden und darum schlägt ein == Vergleich fehl.

Stimmt, hat aber auch noch keiner hier gemacht. currymutze ist ja schon froh, wenn die auf 2 Dezimalstellen gerundete Float-Zahl in der Anzeige auf .00 endet und im Ganzzahl-Teil so aussieht wie sein Anfangswert.

Float Vergleich besser als Subtraktion beider zu vergleichender Werte

Das ist egal. In beiden Fällen treten die gleichen Gleitkomma-Rundungseffekte auf.

void setup()
{
  Serial.begin(115200);
  
float a = PI;
float delta = 1.e-7;
float b = a + delta;

if ( ( a == b )  ^ (( a-b ) == 0.0 ) )
{
   Serial.println( "Vergleich und Subtraktion sind verschieden ?! " );
   Serial.print (a==b); Serial.print( " -- " ); Serial.print( ( a-b ) == 0.0  );
   Serial.print( " :  " ); Serial.println (a-b,10);
}
else  
   if ( a==b) Serial.println (" Delta ist zu klein ");
   else           Serial.println (" Delta is gross geug, um einen Unterschied zu machen"); 

}

void loop() {}

oder findet jemand ein delta, wo ( a==b ) etwas anderes liefert als ( (a-b) == 0 ) ...

michael_x:

Vergleiche von Float Variablen ist gefährlich. Durch Rundungsfehler sind die Zahlen leicht etwas verschieden und darum schlägt ein == Vergleich fehl.

Stimmt, hat aber auch noch keiner hier gemacht.

michael_x hat ein Beispiel gepostet und ich bezog mich darauf:

Ansonsten  ist das natürlich  auch richtig:
if  (  (3877L * 255) / 255  == 3877L ) Serial.println ("Was sonst ?");

Grüße Uwe