DEUTSCH Fibonacci Rechner -> Rundungsfehler <-

Hallo zusammen,

mag mir bitte jemand weiterhelfen, wie ich die Rundungsfehler und overflow Probleme beheben kann?

Ich danke Euch vielmals!

Max :slight_smile:

Variante 1 mit simpler Addition (Rundungsfehler ab Nr.36 & ovf.)

/* Fibonacci Rechner mit Fehlererkennung bis zur 100ten Fib-Zahl.
 * var.1
 */
//Ein/Ausgaenge
const int error = 12;
//Konstanten
const int TON = 25; //Pausenzeit
//Variablen
unsigned int fpos = 0;
unsigned int fail = 0;
double fib = 0;
double x_a = 0;
double x_b = 1;
double f_check = 0;
//Arrays
double check[50]={1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,
10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,
5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,
433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025};
/*

//FEHLER AB Nr.36 24157816.00

51  20365011074
52  32951280099
53  53316291173
54  86267571272
55  139583862445
56  225851433717
57  365435296162
58  591286729879
59  956722026041
60  1548008755920
61  2504730781961
62  4052739537881
63  6557470319842
64  10610209857723
65  17167680177565
66  27777890035288
67  44945570212853
68  72723460248141
69  117669030460994
70  190392490709135
71  308061521170129
72  498454011879264
73  806515533049393
74  1304969544928660
75  2111485077978050
76  3416454622906710
77  5527939700884760
78  8944394323791460 //(ende von Double 16 Stellen?)
79  14472334024676200
80  23416728348467700
81  37889062373143900
82  61305790721611600
83  99194853094755500
84  160500643816367000
85  259695496911123000
86  420196140727490000
87  679891637638612000
88  1100087778366100000
89  1779979416004710000
90  2880067194370820000
91  4660046610375530000
92  7540113804746350000
93  12200160415121900000
94  19740274219868200000
95  31940434634990100000
96  51680708854858300000
97  83621143489848400000
98  135301852344707000000
99  218922995834555000000
100 354224848179262000000

*/

void setup() {
  pinMode(error, OUTPUT);
  Serial.begin(19200);
  delay(100);
  Serial.println(F(" "));
  Serial.println(F("Fibonacci Zahlen mit Kontrollfunktion bis 100"));
  Serial.println(F(" "));
  delay(100);
}

void loop() {
 fpos++;
 fib = x_a + x_b;
 delay(TON);
 x_a = x_b;
 delay(TON);
 x_b = fib;
 delay(TON);
 f_check = check[fpos];
 Serial.print(F("Nr."));
 Serial.print(fpos);
 delay(TON);

if (f_check == fib) {
  digitalWrite(error, LOW);
  Serial.print(F("  Ergebnis plausibel"));
  Serial.print(F(" Ist-Wert = "));
  Serial.println(fib);
}
else {
  analogWrite(error, 120); //LED ohne Vorwiderstand
  fail++;
  Serial.println(F(" "));
  Serial.print(F("RECHEN_FEHLER Nr."));
  Serial.println(fail);
  Serial.print(F("Soll-Wert = "));
  Serial.println(f_check);
  Serial.print(F("Ist-Wert = "));
  Serial.println(fib);
  Serial.println(F(" "));
  delay(2000);
 }
if (fpos == 49) { //maximal Wert des Arrays-1 festlegen
  fpos = 0;
  fib = 0;
  x_a = 0;
  x_b = 1;
  Serial.println(F(" "));
  Serial.println(F("****RESET****"));
  Serial.println(F(" "));
  delay(TON);
 }
}

Variante 2 mit pow() (Rundungsfehler durch pow() & ovf.)

const int fehler_led = 12;

const int TON = 1;  //delay Zeit
unsigned int fib_n = 0; //zu errechnende Fibonacci-Zahl
double fib = 0;
double pow_1 = 0;
double pow_2 = 0;

double const_0 = 0;
//(5^0,5) = 2,2360679774997896964091736687313

double const_1 = 0;
//1/(5^0,5) = 0,44721359549995793928183473374625

double const_2 = 0;
//(5^0,5)/2 = 1,1180339887498948482045868343656

double const_3 = 0;
//(1-(5^0,5)) = -1,2360679774997896964091736687313


void setup()
{
  pinMode(fehler_led, OUTPUT);
  
  Serial.begin(19200);
  delay(TON);
  Serial.println(F("Fibonacci Rechner 1.0 Arduino"));
  delay(TON);
  
  const_0 = pow(5, 0.5);
  delay(TON);
  Serial.print(F("const_0 = "));
  Serial.print(const_0, DEC);
  Serial.println(F("  Soll = 2.2360680103"));
  delay(TON);
  
  const_1 = 1/const_0;
  delay(TON);
  Serial.print(F("const_1 = "));
  Serial.print(const_1, DEC);
  Serial.println(F("  Soll = 0.4472135901"));
  delay(TON);
  
  const_2 = const_0/2;
  delay(TON);
  Serial.print(F("const_2 = "));
  Serial.print(const_2, DEC);
  Serial.println(F("  Soll = 1.1180340052"));
  delay(TON);
  
  const_3 = 1-const_0;
  delay(TON);
  Serial.print(F("const_3 ="));
  Serial.print(const_3, DEC);
  Serial.println(F("  Soll =-1.2360680103"));
  
  Serial.println(F(" "));
  delay(1000);
}

void loop()
{
  //(1/(const_0))*((((const_0)/2)^fib_n)-((1-const_0)/2)^fib_n)
  //   (const_1) *   ((const_2)  ^fib_n)-   ((const_3)  ^fib_n)
  //   (const_1) *            pow_1     -          pow_2
  
  fib_n++;
  pow_1 = pow(const_2, fib_n);
  delay(TON);
  //Serial.print(F("pow_1 = "));
  //Serial.println(pow_1, DEC);
  //delay(TON);
  
  pow_2 = pow(const_3, fib_n);
  delay(TON);
  //Serial.print(F("pow_2 = "));
  //Serial.println(pow_2, DEC);
  //delay(TON);
  
  fib = const_1 * (pow_1 - pow_2);
  delay(TON);
  
  Serial.print(F("Fibonacci Pos. = "));
  Serial.println(fib_n);
  Serial.print(F("Fibonacci Zahl = "));
  Serial.println(fib);
  Serial.println(F(" "));
  if(fib == (fib+fib)/2) {
    digitalWrite(fehler_led, LOW);
  }
  else {
    analogWrite(fehler_led, 120);
    Serial.println(F("********FEHLER********"));
    delay(1000);
  }
  delay(TON);
}

Hallo,

auf Arduinos mit 8 Bit Prozessoren gibt es kein echtes double. Da ist das mit float identisch, hat also nur 6-7 Stellen.

Für Rechnungen mit großen ganzen Zahlen macht float wenig Sinn. Das größte was da verfügbar wäre ist unsigned long mit 32 Bit. 64 Bit Ganzzahlen gibt es meines Wissens nach auch nicht auf den 8 Bittern.

Float, was double entspricht, belegt 4 Byte und hat nur 6 bis 7 significante Stellen. Darum sind diese Rundungsfehler fisiologisch.
Um mehr Genauigkeit zu haben mußt Du selbst Routinen schreiben um mit Variablen mit mehr Bytes rechnen zu können.
Grüße Uwe

Evtl. könnte Dir das helfen.

Gruß Tommy

Edit: Den ganzen Thread lesen.

Abhängig von Deinem Projekt könnte auch ein Teensy 3.5 "120 MHz ARM Cortex-M4 with Floating Point Unit" hilfreich sein. Praktische Erfahrungen habe ich aber damit leider noch nicht.

Mein Teensy 3.2 "32 bit ARM Cortex-M4 72 MHz CPU" spuckt dies aus:

Fibonacci Zahlen mit Kontrollfunktion bis 100

Nr.1 Ergebnis plausibel Ist-Wert = 1.00
Nr.2 Ergebnis plausibel Ist-Wert = 2.00
Nr.3 Ergebnis plausibel Ist-Wert = 3.00
Nr.4 Ergebnis plausibel Ist-Wert = 5.00
Nr.5 Ergebnis plausibel Ist-Wert = 8.00
Nr.6 Ergebnis plausibel Ist-Wert = 13.00
Nr.7 Ergebnis plausibel Ist-Wert = 21.00
Nr.8 Ergebnis plausibel Ist-Wert = 34.00
Nr.9 Ergebnis plausibel Ist-Wert = 55.00
Nr.10 Ergebnis plausibel Ist-Wert = 89.00
Nr.11 Ergebnis plausibel Ist-Wert = 144.00
Nr.12 Ergebnis plausibel Ist-Wert = 233.00
Nr.13 Ergebnis plausibel Ist-Wert = 377.00
Nr.14 Ergebnis plausibel Ist-Wert = 610.00
Nr.15 Ergebnis plausibel Ist-Wert = 987.00
Nr.16 Ergebnis plausibel Ist-Wert = 1597.00
Nr.17 Ergebnis plausibel Ist-Wert = 2584.00
Nr.18 Ergebnis plausibel Ist-Wert = 4181.00
Nr.19 Ergebnis plausibel Ist-Wert = 6765.00
Nr.20 Ergebnis plausibel Ist-Wert = 10946.00
Nr.21 Ergebnis plausibel Ist-Wert = 17711.00
Nr.22 Ergebnis plausibel Ist-Wert = 28657.00
Nr.23 Ergebnis plausibel Ist-Wert = 46368.00
Nr.24 Ergebnis plausibel Ist-Wert = 75025.00
Nr.25 Ergebnis plausibel Ist-Wert = 121393.00
Nr.26 Ergebnis plausibel Ist-Wert = 196418.00
Nr.27 Ergebnis plausibel Ist-Wert = 317811.00
Nr.28 Ergebnis plausibel Ist-Wert = 514229.00
Nr.29 Ergebnis plausibel Ist-Wert = 832040.00
Nr.30 Ergebnis plausibel Ist-Wert = 1346269.00
Nr.31 Ergebnis plausibel Ist-Wert = 2178309.00
Nr.32 Ergebnis plausibel Ist-Wert = 3524578.00
Nr.33 Ergebnis plausibel Ist-Wert = 5702887.00
Nr.34 Ergebnis plausibel Ist-Wert = 9227465.00
Nr.35 Ergebnis plausibel Ist-Wert = 14930352.00
Nr.36 Ergebnis plausibel Ist-Wert = 24157817.00
Nr.37 Ergebnis plausibel Ist-Wert = 39088169.00
Nr.38 Ergebnis plausibel Ist-Wert = 63245986.00
Nr.39 Ergebnis plausibel Ist-Wert = 102334155.00
Nr.40 Ergebnis plausibel Ist-Wert = 165580141.00
Nr.41 Ergebnis plausibel Ist-Wert = 267914296.00
Nr.42 Ergebnis plausibel Ist-Wert = 433494437.00
Nr.43 Ergebnis plausibel Ist-Wert = 701408733.00
Nr.44 Ergebnis plausibel Ist-Wert = 1134903170.00
Nr.45 Ergebnis plausibel Ist-Wert = 1836311903.00
Nr.46 Ergebnis plausibel Ist-Wert = 2971215073.00
Nr.47 Ergebnis plausibel Ist-Wert = 4294967295.//
Nr.48 Ergebnis plausibel Ist-Wert = 4294967295.//
Nr.49 Ergebnis plausibel Ist-Wert = 4294967295.//

RESET

Ja, die Teensy können mit double rechnen, aber

  1. die FPU beim Teensy 3.5 und 3.6 kann nur float. (Eine FPU für double wird es wohl beim zukünftigen Teensy 4 mit Cortex M7 geben.)

  2. beim Teensy ist standardmäßig der Compilerschalter gesetzt, der dafür sorgt das Fliesskommakonstanten im Quelltext als float betrachtet werden. Nützt also nix, wenn man ganz tolle lange Kommazahlen in seinen Quelltext schreibt. In obigem Code wird allerdings von long konvertiert, deshalb geht das.

  3. Auf dem Teensy sollten auch int64_t und uint64_t zur Verfügung stehen. Für Fibonaccizahlen sicher besser geeignet.

ArduFE:
3) Auf dem Teensy sollten auch int64_t und uint64_t zur Verfügung stehen.

Die Datentypen stehen auf jedem Arduino zu Verfügung,
Eingabe und Ausgabe wird allerdings nicht direkt unterstützt.

uwefed:
Um mehr Genauigkeit zu haben mußt Du selbst Routinen schreiben um mit Variablen mit mehr Bytes rechnen zu können.

Danke schonmal!

Wie genau haben diese Routinen denn auszusehen?
Stelle mir das in etwa so vor, dass immer Teilabschnitte hintereinander ausgegeben werden wie bei BigNumber?

Ich habe mir da noch keine Gedanken gemacht aber ich vermute das würde so aussehen wie Du mit Stift und Papier eine Addition, Multiplikation ecc ausführen würdest.
Grüße Uwe

Hierbei vermutet Uwe schon sehr richtig. Egal welcher Rechner - die Wortbreite ist immer sehr begrenzt. Daher arbeitet man bei sehr große Zahlen meines Wissens nach mit String-Ketten, die Ziffer für Ziffer zerlegt werden. Vor Jahren hatte ich mich auch damit befasst; vielleicht hilft dir folgende Seite dazu weiter:

Hilft jetzt nicht gerade bei deinem Problem, aber wenns dir ums rechnen geht: schau dir mal Python an

Fibonacci geht dort verdammt weit. Die höchste Zahl die ich dort mal berechnet hatte, hatte etwas über 2 * 10^7 Stellen...

Grüsse
Peter

someone83:
Hilft jetzt nicht gerade bei deinem Problem, aber wenns dir ums rechnen geht: schau dir mal Python an

BigInteger/BigNumber Klassen um sowas zu berechnen gibt es in vielen Sprachen

Aber mal eine ganz andere Frage: ist das originale Problem eine akademische Übung, oder warum möchte man auf einem Mikrocontroller Fibonacci-Zahlen berechnen?
:slight_smile:

olf2012:
Aber mal eine ganz andere Frage: ist das originale Problem eine akademische Übung, oder warum möchte man auf einem Mikrocontroller Fibonacci-Zahlen berechnen?
:slight_smile:

Gute Frage :slight_smile:

Habe etwas Langeweile bekommen und wollte mal mit großen Zahlen rechnen.

Es gibt doch Zehntausende andere Möglichkeiten sich die Zeit mit Arduino zu vertreiben ... :wink: :wink: :wink: :wink:

Hab eine neue Beschäftigung gefunden :confused:

Kann mir bitte jemand weiterhelfen, wie ich die "delay" Funktion umgehe?
Das hatte mir mit einer Ein- sowie Ausschaltverzögerung nicht geholfen:

// Max B. 04.09.2017
// Ein/Ausgaenge
const int LED_1 = 11; //(UNO PWM Ausgaenge = 11,10,9,6,5,3)
// Standartwerte
unsigned int stufe_1 = 0;
unsigned int stufe_2 = 0;
unsigned int zeit_1 = 0;
unsigned int zeit_2 = 0;
// Merker
unsigned int frage_Rv = 0;
bool merker_1 = 1;
// Variablen
unsigned int limit = 0;
unsigned long v_zeit_1 = 9999999;
unsigned long v_zeit_2 = 9999999;
unsigned long akt_zeit = 0;


void setup() {

 Serial.begin(19200); /*----19200----*/
  pinMode(LED_1, OUTPUT);
 while (!Serial) { }
  Serial.println(F("\nHaben Sie einen Vorwiderstand verbaut? y=1 n=2"));
}

void loop() {

 while (frage_Rv == 0) {
  frage_Rv = Serial.parseInt();
  frage_Rv = constrain(frage_Rv, 0, 2);
 }
if (limit == 0) { 
 Serial.println(F("\nEingabe als String (stufe_1 zeit_1 stufe_2 zeit_2)"));
 
switch (frage_Rv) {
  case 1:
  Serial.println(F("  max. mit Rv     (  255     xx     255     xx  )"));
  limit = 255;
  break;
  case 2:
  Serial.println(F("  max. ohne Rv      (  150     xx     150     xx  )"));
  limit = 150;
  break;
  }
 } 
 // solange serielle Eingabe vorhanden
 while (Serial.available() > 0) {

    // int Wert wird gesucht
    stufe_1 = Serial.parseInt();
    // wiederholen
    zeit_1 = Serial.parseInt();
    // wiederholen
    stufe_2 = Serial.parseInt();
    // wiederholen
    zeit_2 = Serial.parseInt();
  
    // constrain = limit von 0 bis x (~map)
    stufe_1 = constrain(stufe_1, 0, limit); //max. 255
    stufe_2 = constrain(stufe_2, 0, limit); //ohne Rv ~150

    // wenn neue Zeile eingegeben
   if (Serial.read() == '\n') {
      
     Serial.print(F("\nstufe_1 = "));
     Serial.print(stufe_1);
     Serial.print(F("/"));
     Serial.println(limit);
     
     Serial.print(F(" zeit_1 = "));
     Serial.print(zeit_1);
     Serial.println(F("ms"));
     
     Serial.print(F("stufe_2 = "));
     Serial.print(stufe_2);
     Serial.print(F("/"));
     Serial.println(limit);
     
     Serial.print(F(" zeit_2 = "));
     Serial.print(zeit_2);
     Serial.println(F("ms"));
   }
 }
 akt_zeit = millis();
 
 if ((akt_zeit - v_zeit_1 >= zeit_1) && merker_1 == 1) { //----Problem Zone----
  analogWrite(LED_1, stufe_1);
  v_zeit_1 = akt_zeit;
  merker_1 = 0;
  Serial.println(F("DEBUG pos. 1"));
 }
 if ((akt_zeit - v_zeit_2 >= zeit_2+zeit_1) && merker_1 == 0) {
  analogWrite(LED_1, stufe_2);
  v_zeit_2 = akt_zeit;
  merker_1 = 1;
  Serial.println(F("DEBUG pos. 2"));
 }
}

Meinst Du nicht, dass zu einem neuen Thema auch ein neuer Thread passt?
Das hat ja mit dem ursprünglichen Thema nichts zu tun.

Gruß Tommy