Forum: Mikrocontroller und Digitale Elektronik Arduino: double test = pow((float)20.0,(float)10.0) kein sinnvolles Ergebnis?


von Seppel (Gast)


Lesenswert?

Hallo,

ich ärgere mich seit einigen Tagen mot pow() herum:


Führe ich das mit 20.0^5.0 aus:
double test = pow((float)20.0,(float)10.0)
Dann ist das Ergebnis korrekt:

0x0030D400
3200000.00


Führe ich das mit 20.0^10.0 aus:
double test = pow((float)20.0,(float)10.0)
Dann ist das Ergebnis Falsch:

FFFFFFFF
ovf


Eigentlich ist der float Wertebereich(double ist bei den 8Bit AVR's 
gleich) bis 3.403E+38, 20^10 (1.024E+13 ) passt also locker rein.

Was geht da ab, was mache ich falsch?

Vielen Dank,

Grüße

Seppel

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Seppel schrieb:
> Dann ist das Ergebnis korrekt:
>
> 0x0030D400

Das ist kein Float. Wie erzeugst Du dieses "Ergebnis"?

In Deiner Variablen "test" steht das so sicher nicht drin.

von Seppel (Gast)


Lesenswert?

Hallo Rufus,

Serial.println((uint32_t)test,HEX);

Sollte aber passen, float hat:

1 Signed-Bit
8 Exponenten-Bits
23 Fraction Bits

Grüße

Seppel

von Marcel (Gast)


Lesenswert?

Seppel schrieb:
> Serial.println((uint32_t)test,HEX);

Das geht schief. 20^10 ist 10.240.000.000.000. Das ist bedeutend größer 
als der größte mit uint32_t repräsentierbare Wert.

Viele Grüße,
Marcel

von Seppel (Gast)


Lesenswert?

Hallo Macel,

hast Du einen anderen Vorschlag wie ich es auf der seriellen 
Schnittselle ausgeben kann?

Vielen Dank,

Seppel

von Seppel (Gast)


Lesenswert?

P.S.

Wenn man dem Tool glauben mag:

https://www.h-schmidt.net/FloatConverter/IEEE754.html

Dann ist:

1.024E13
0x551502f9

Also ich hänge irgendwie fest,... .

Grüße

Seppel

von Marcel (Gast)


Lesenswert?

Hallo Seppel,

ich glaube, da liegt ein Missverständnis vor.
Mit "(uint32_t) test" wird der Floating-Point-Wert in einen Integer 
umgewandelt und nicht nur als Integer interpretiert.
Entsprechend dem von dir verlinkten Tool möchtest du folgendes 
erreichen:

Serial.println(*reinterpret_cast<uint32_t*>&test, HEX);

Viele Grüße,
Marcel

von Marcel (Gast)


Lesenswert?

Die Klammern gingen eben verloren. Richtig heißen muss es natürlich:

Serial.println(*reinterpret_cast<uint32_t*>(&test), HEX);

von Seppel (Gast)


Lesenswert?

Hallo,

hab's mit einem pointer gelöst, nicht schön(ja richtig böse),... aber 
geht auch.

----------------------------------------------------------------------

Ich hab folgendes probiert:

  float mytest2 = 1.024E13;
  uint32_t* oh = (uint32_t*)&mytest2;
  Serial.println("Test2");
  Serial.println((uint32_t)*oh,HEX);

Das Ergebnis ist:

Test2
551502F9

-------------------------------------

Also, wie zu erwarten war, float (IEEE754) kann 1.024E13 darstellen, das 
ist schon mal gut dass das klappt.



----------------------------------------------------------------------

Da ich nur ganzzahlige Exponenten brauche hab ich mir eine Funktion 
selbst geschrieben:

double myPow (double base, uint8_t exponent)
{
  uint8_t iter = (exponent-1U);
  double result = base;
   for ( ; (iter>0) ; (iter=iter-1) )
   {
     result = (result * base);
   }
   return result;
}

-------------------------------------
Geht immer noch nicht. Wahrscheinlich liegt das daran dass mit 
steigendem Iterator eine große mit einer kleinen Zahl multipliziert wird 
und dann die Ungenauigkeiten ein sinnvolles Ergebnis verhindern, sicher 
bin ich aber nicht.

----------------------------------------------------------------------

Hat jemand eine Idee wie ich das läsen kann?

Vielen Dank,

Grüße

Seppel

von Peter II (Gast)


Lesenswert?

Seppel schrieb:
> Hat jemand eine Idee wie ich das läsen kann?

was ist das genau Problem? Willst du einen Rechnen per Seriell 
programmieren oder hat da ganze auch einen Zweck?

Es mag ja Anwendungen geben, wo man so große Zahlen fast ohne 
Genauigkeit braucht, aber mir ist bis jetzt keine untergekommen.

von Seppel (Gast)


Lesenswert?

P.S.

Und jetzt kommt der Knaller:

double myPow10 (double base)
{
  return (
    (((base*base)*(base*base))*((base*base)*(base*base)*(base*base)))
    );
}

Es geht,....

Kann mir jemand erklären was da schief läuft wenn man das mit einer for 
Loop macht?

Vielen Dank,

Grüße

Seppel

von Dirk B. (dirkb2)


Lesenswert?

Seppel schrieb:
> Da ich nur ganzzahlige Exponenten brauche hab ich mir eine Funktion
> selbst geschrieben:

Warum?
Soll die schneller und/oder genauer sein?

Meist weiß der Compiler selber besser, wann er pow ersetzen kann.
(macht er, wenn z.B. der Exponent konstant und klein ist)

von Seppel (Gast)


Lesenswert?

Hallo Dirk,

Mit der von mir geschriebenen "Hard Coded" 20.0^10 funktioniert es, mit 
pow nicht. Ich weiß auch nicht was Du mit "Meist weiß der Compiler 
selber besser, wann er pow ersetzen kann." meinst.

Und nein, in der Applikation sind die Exponenten nicht konstant, nur 
ganzzahlig.

Grüße

Seppel

von Nop (Gast)


Lesenswert?

Seppel schrieb:
> hab's mit einem pointer gelöst, nicht schön(ja richtig böse),... aber
> geht auch.

Das nennt sich Pointer Type Punning und ist undefiniertes Verhalten, 
weil es zugleich auch Pointer Aliasing ist. Kann gehen, kann auch 
jederzeit nicht gehen. Type Punning würde ich über eine Union machen.

von Seppel (Gast)


Lesenswert?

Hallo,

aber warum es mit der selbst geschriebenen Funktion"myPow10" klappt und 
mit pow(x,10) nciht`?

Grüße

Seppel

von Dumdi D. (dumdidum)


Lesenswert?

Seppel schrieb:
> ber warum es mit der selbst geschriebenen Funktion"myPow10" klappt und
> mit pow(x,10) nciht`?

Da müsstest Du mal genau posten (komplettes Beispiel) wie Du das 
überprüfst.

von eProfi (Gast)


Lesenswert?

Nach jedem Schleifendurchlauf das Zwischenergebnis ausgeben.

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.