Fehler in Fact

Begonnen von alexdrik, 15. März 2011, 20:56:18

Vorheriges Thema - Nächstes Thema

0 Mitglieder und 1 Gast betrachten dieses Thema.

alexdrik

Hallo,

der Baustein FACT liefert für 13 einen falschen Wert zurück.
Richtig wäre 6227020800, das ist aber mit DINT nicht darstellbar, deswegen wird 1932053504 zurückgeliefert.
Außerdem liefert FACT für negative Werte nicht -1 zurück, sondern die Fakultät des positiven Wertes.

Wäre es nicht effektiver, die Werte vorzuberechnen und mittels CASE auszuwählen?

CASE x OF
  0: fact :=                                      1;
  1: fact :=                                      1;
  2: fact :=                                      2;
  3: fact :=                                      6;
  4: fact :=                                    24;
  5: fact :=                                  120;
  6: fact :=                                  720;
  7: fact :=                                5040;
  8: fact :=                              40320;
  9: fact :=                            362880;
10: fact :=                         3628800;
11: fact :=                       39916800;
12: fact :=                     479001600;
(* für 64Bit-Werte
13: fact :=                   6227020800;
14: fact :=                 87178291200;
15: fact :=             1307674368000;
16: fact :=           20922789888000;
17: fact :=         355687428096000;
18: fact :=       6402373705728000;
19: fact :=   121645100408832000;
20: fact := 2432902008176640000;
*)
ELSE
    fact_ad :=                                 -1;
END_CASE



hugo

den ferhler mit 13 werden wir prüfen,
allerdings -1 für negative werte ist schlichtweg falsch, fakultät für negative werte ist nicht definiert und deshalb ist auch die antwort -1 falsch.
das wäre geleichbedeutend als für 34/0 eione -1 zurückzuliefern.

wie bei jeder mathematischen funktion muss der programmierer den wertebereich einhalten.

alexdrik


Hmmm, wenn man die Werte in ein Array packt, dann hat man das Problem mit den negativen Werten nicht.
Vorberechnen kann man di dann auch:

Deklaration:
   werte : ARRAY[0..12] OF DINT :=1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600;

Implementation:
     IF X > 12 THEN
        Fact := -1;
     ELSE
        Fact := werte
  • ;
         END_IF

hugo

die fact von 13 haben wir ausgeschlossen, den sie übersteigt den wertebereich von dint.
die lösung mittels array sieht zwar super aus, ist aber bedeutend langsamer weil bei jedem asufruf das ganze array auf den stack kopiert werden muss
in release 332 wird der fehler korrigiert

alexdrik

Hallo,

wenn man das Array in die Struktur CONSTANTS_MATH aufnimmt, dann wird es einmal global angelegt und nicht jedesmal in den Stack kopiert werden.

hugo

richtig das werde ich mir nochmal ansehen

hugo

fact mittels array ist ca doppelt so schnell, habe ich entsprechend realisiert