Forum: Compiler & IDEs Paramterübergabe pow


von TechInfo (Gast)


Lesenswert?

Habe eine Rundungsfunktion, die als Parameter die zu rundende Zahl 
erhält sowie Anzahl der Stellen, auf die gerundet werden soll. Z.B.

Round (1.123, 2.0) ergibt 1.12

Ausschnitt:

double Round(double Zahl, double Stellen)
{

int i=0;
i=pow(10, Stellen);

[...]

Das funktioniert für 2 Stellen auch wunderbar. Wenn ich aber "3" für 
Stellen eingebe, wird i zu 0 anstatt 1000. Bei allen Werten größer als 
"3" wird i zu 1.

Die pow-Funktion scheint in Ordnung zu sein, denn mit Konstanten 
funktioniert sie. Es scheint also an der Parameterübergabe zu liegen.

Hat jemand eine Idee?

von yalu (Gast)


Lesenswert?

Das sollte normalerweise funktionieren, solange der Wertebereich von int 
nicht überschritten wird. Schau mal nach, wie groß die ints auf deinem 
Zielprozessor sind. Bei 16 Bit sollte 10 hoch 3 noch darstellbar sein, 
10 hoch 4 aber nicht mehr. Hast du einen AVR und beim Compiler -mint8 
eingestellt? Dann ist schon bei 10 hoch 2 Schluss.

Was du zusätzlich beachten solltest: Je nach Implementation von pow() 
kann es passieren, dass bspw. 10 hoch 3 nicht 1000, sondern 999.9999 
ergibt. Die Umwandlung nach int ergibt dann 999, was sicher nicht deinen 
Vorstellungen entspricht.

Aus den genannten Gründen würde ich das i als double deklarieren. Aber 
auch dann hast du natürlich immer noch das Problem, dass das gerundete 
Ergebnis (z. B. 1.234) intern nicht immer exakt darstellbar ist und 
durchaus auch 1.233999 oder 1.234001 sein kann.

von Karl H. (kbuchegg)


Lesenswert?

yalu wrote:

> Aus den genannten Gründen würde ich das i als double deklarieren. Aber
> auch dann hast du natürlich immer noch das Problem, dass das gerundete
> Ergebnis (z. B. 1.234) intern nicht immer exakt darstellbar ist und
> durchaus auch 1.233999 oder 1.234001 sein kann.

Um das weiterzuführen:

Das ist aber kein Problem. Da macht man eine Rundungskorrektur
dran und fertig:

  i = (int)( pow(10, Stellen) + 0.5);

Aber ganz was anderes in diesem Zusammenhang.
pow() ist eine teure Funktion!
Und jetzt stell ich mal die Frage, was denn übliche Werte für
Stellen sein könnten. Ich wage mal die Behauptung, dass ausser
den Werten 0, 1, 2, 3, 4, 5, 6 praktisch keine anderen Werte
vorkommen werden.

Ergo würde ich das ganze komplett ohne pow machen und stattdessen
eine Tabelle nehmen (und Stellen als int ausführen. Du kannst keine
2.5 Nachkommastellen haben. unsigned int wäre noch besser, aus
praktischen Gründen belasse ich es aber bei int).
1
long Faktoren[] = { 1, 10, 100, 1000, 10000, 100000, 10000000 };
2
3
double Round(double Zahl, int Stellen)
4
{
5
  if( Stellen >= sizeof( Faktoren ) / sizeof( *Faktoren ) )
6
    Stellen = sizeof( Faktoren ) / sizeof( *Faktoren ) - 1;
7
  if( Stellen < 0 )
8
    Stellen = 0;
9
10
  long i = Faktoren[Stellen];
11
12
  ...

Das dürfte
* um einiges schneller sein
* wenn pow() sonst nirgends im Pgm gebraucht wird auch um
  einiges platzsparender sein.

Allerdings:
Es löst nicht das ursprüngliche Problem, zu dem ich auch keine
Idee habe was da schiefgelaufen sein könnte.



von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger wrote:

> Allerdings:
> Es löst nicht das ursprüngliche Problem, zu dem ich auch keine
> Idee habe was da schiefgelaufen sein könnte.

Ach das war ja wieder TechInfo mit seinem Xilinx (oder wie
das heist) System bei dem der Compiler anscheinend hinten
und vorne Probleme mit Floating Point hat.

Was sagt eigentlich der Compiler Hersteller zu deiner
mitlerweile nicht unbedeutenden Latte von Fehlern?

von TechInfo (Gast)


Lesenswert?

@yalu

Mit i als double habe ich genau das gleiche Problem.

@Karl-Heinz

Kannst du mir deinen Code mal genauer erklären?

Größe von Faktoren durch Größe vom Inhalt von Faktoren? Häh? ;)

Ich bin mir nicht sicher ob diese Probleme vom Compiler her rühren. Die 
treten ja anscheinend immer dann auf, wenn Funktionen mit viel 
Stackbedarf verwendet werden (schätze mal, pow gehört dazu).

Andererseits gibt es auch im zugehörigen GNU-Debugger Probleme, manche 
Variablen-Inhalte werden falsch angezeigt obwohl intern alles richtig 
ist...

Der Xilinx-Distributor hat übrigens keine Ahnung und empfiehlt: "Neue 
Version bei uns kaufen!" ;)

Na vielen Dank...

von Karl H. (kbuchegg)


Lesenswert?

TechInfo wrote:

> Größe von Faktoren durch Größe vom Inhalt von Faktoren? Häh? ;)

Das ist die übliche Art und Weise wie man eine Arraygröße
feststellen kann ohne die Zahl selbst in den Code mit
aufzunehmen:

   Größe_vom_kompletten_Array / Größe_des_ersten_Array_Elementes

  T Feld[] = { .... }

Größe des kompletten Arrays in Bytes
  sizeof( Feld )

Größe des ersten Array Elements in Bytes
  sizeof( *Feld )    oder
  sizeof( Feld[0] )  oder
  sizeof( T )

Die Anzahl der Elemente ist daher

  sizeof( Feld ) / sizeof( *Feld )

Sieht wild aus, wird aber vom Compiler berechnet und kostet
daher nichts zur Laufzeit.

Vorteil:
Die fügst eine weitere Zahl zur Initialisierung dazu und um den
Rest kümmert sich der Compiler.

von TechInfo (Gast)


Lesenswert?

Ok, verstanden, vielen Dank.

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.