Go Down

Topic: OVF (stack overflow) when calculating a 5th order polynomial on an UNO (Read 5 times) previous topic - next topic

MichaelMeissner

Well, if you are doing polynomial calculations on the Uno, note that the all of the AVR processors map 'double' into 'float', which means reduced precision and exponent range.  Arm based processors like Due or a Teensy 3.0 use the same format for double as x86's.

Another note, if you are doing lots of floating point calculations, both the AVR and Due/Teensy 3.0 based processors do not have floating point hardware, and emulate the floating point.  If you are doing lots of floating point calculations, perhaps you would do better to get something like a Raspberry Pi/Beagle Board/maybe pcDunio which has hardware floating point to do the calculations.  Since these machines run Linux varients, they also have much more memory to work with.  But the programming of these is different from the Arduino, and you have less pins for controlling hardware.  If you are controlling devices, perhaps a combination, where you use the R-PI to do the brain work, and a controller to talk to hardware.

robtillaart

Interesting to see some of my code back ;)

Some Arduino floating points points:
- the Arduino has only 7 digits of precision, the compiler will take care of rounding
- the compiler accepts E notation in float constants, which removes unneeded pow(10, n) from your code
- a fifth order polynome with integer powers can speed up by a big factor by decomposing it using only 5 multiplies and 5 additions.

Code: [Select]

void setup()
{
  Serial.begin(9600);
  Serial.println("start...");
 
  long val = 420;

  f = 1.354026784*pow(10,-8)*pow(val,5) //pow(10,-8) raises 1.354026784 to the 10-8
               - 2.559722383*pow(10,-5)*pow(val,4)
               + 0.0192917182*pow(val,3)
               - 7.24448384*pow(val,2)
               + 1356.112407*val
               - 101259.7822;
               
  Serial.println(f,5);
  Serial.println(float2s(f, 5));

  // removing pow() completely
  f = 1.354026784E-8* val*val*val*val*val - 2.559722383E-5* val*val*val*val + 1.92917182E-2 * val*val*val - 7.24448384 * val*val + 1356.112407*val - 101259.7822;
  Serial.println(f,5);
  Serial.println(float2s(f,5));
 
  // minimize math
  f = (((( 1.354026784E-8 * val - 2.559722383E-5 ) * val + 1.92917182E-2 ) * val - 7.24448384 ) * val + 1356.112407) * val - 101259.7822;
  Serial.println(f,5);
  Serial.println(float2s(f, 5));
}

void loop(){}


Quote
116.9063


output
start...
116.90625
1.16906 E+2

116.84375
1.16843 E+2

116.79688
1.16796 E+2

Note that method 2 and 3 which uses less operations already differ in the 4th digit, so calculating this with more than 5 digits is speculative at best.

This is caused by the fact that all the partial sums  ( a.pow(b,n) ) are in the same order of magnitude 10^5..10^6 and their sum is 2 to 3 orders of magnitude lower.
(you're losing significant bits here)

BTW according to Excel the "right" value == 116.935898400974 so simplifying the math does make it worse this time.

Excel snippet (,'s are due to localization)
Code: [Select]

coefficient             420^n                   partial result
1,354026784000000E-08 1,306912320000000E+13 1,769594285619580E+05
-2,559722383000000E-05 3,111696000000000E+10 -7,965077900291570E+05
1,929171820000000E-02 7,408800000000000E+07 1,429284818001600E+06
-7,244483840000000E+00 1,764000000000000E+05 -1,277926949376000E+06
1,356112407000000E+03 4,200000000000000E+02 5,695672109400000E+05
-1,012597822000000E+05 1,000000000000000E+00 -1,012597822000000E+05

                           sum = 1,169358984009740E+02




Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up