Dear Forum,
I have experienced some strange behaviour using float/double values in a formula calculation.
Using the same static double values the result may differ each time I run the calculation?
I'm using a LPC824 (Cortex M0) with no FPU and KEIL-MDK. No MicroLIB and default compiler version 5
I'm aware of the usage of double/float precision issue. But this problem is when using the same values, the result is different each time I run a calculation.
I have a voltage (double) from a ADC, that is run through a formula, that uses 7 coefs (double).
The formula is this:
dResult = V0[paramIndex] + ( (dTemp-T0[paramIndex])*(P1[paramIndex]+(dTemp-T0[paramIndex])*(P2[paramIndex]+(dTemp-T0[paramIndex])*(P3[paramIndex]+P4[paramIndex]*(dTemp-T0[paramIndex]))))/( 1+(dTemp-T0[paramIndex])*(q1[paramIndex]+q2[paramIndex]*(dTemp-T0[paramIndex]))));
V0[], T0[], P1[], P2[], P3[], P4[], q1[] and q2[] contains static double values. So they do neve change.
dTemp is the double value (voltage) passed to the function containing the formula.
If I also keep the dTemp stable (fixed static value of 27.8125) the dResult is different each time I run the formula. If I use the value of 27.7812 it is the same value each time.
Why do I see this behavior? Why is the result not the same each time?
Thomas
Hi,
I will try to make a minimal project to reproduce it. I will return with that
Yes, I mean not static as a keyword, static in not changed. See test code below. I just call the calculation function with data from an array of double.
dResult, dResult1 and dresult in the function below can have different values because of rounding in the double calculation. But also some of the broken down calculation (dCalc11, dCalc2 etc) can have different values with the same data
// Data for the test double fCJTemps[] = {27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125}; int nCount = 16; int nIndex = 0;
// Called from main loop if(nIndex >= nCount) { nIndex = 0; }
dResult = Calculation(fCJTemps[nIndex], 3); nIndex++;
double Calculation(double dTemp, byte paramIndex) {
dTempT0 = 0.0;
dq1q2Temp = 0.0;
dMulti = 0.0;
dDivider = 0.0;
// Broken up formula for the divider
dTempT0 = dTemp-T0[paramIndex];
dq1q2Temp = q1[paramIndex]+q2[paramIndex]*(dTempT0);
dMulti = dTempT0*dq1q2Temp;
dDivider = 1.0+dMulti;
// Broken up formula
dCalc1 = P4[paramIndex]*(dTempT0);
dCalc2 = (P3[paramIndex]+ P4[paramIndex]*(dTempT0));
dCalc3 = (dTempT0)*((P3[paramIndex]+ P4[paramIndex]*(dTempT0)));
dCalc4 = P2[paramIndex]+(dTempT0)*((P3[paramIndex]+ P4[paramIndex]*(dTempT0)));
dCalc5 = (dTempT0)*(P2[paramIndex]+(dTempT0)*((P3[paramIndex]+ P4[paramIndex]* (dTempT0))));
dCalc6 = P1[paramIndex]+dCalc5;
dCalc7 = (dTempT0)*(P1[paramIndex]+dCalc5);
// Result with pre calculated divider
dResult = V0[paramIndex] + ( (dTempT0)*(P1[paramIndex]+(dTempT0)*(P2[paramIndex]+(dTempT0)*(P3[paramIndex]+P4[paramIndex]*(dTempT0))))/(dDivider));
// Result with all formula part pre calculated
dResult1 = V0[paramIndex] + ( dCalc7/(dDivider));
// Result with formula directly calculated
dResult2 = V0[paramIndex] + ( (dTemp-T0[paramIndex])*(P1[paramIndex]+(dTemp-T0[paramIndex])*(P2[paramIndex]+(dTemp-T0[paramIndex])*(P3[paramIndex]+P4[paramIndex]*(dTemp-T0[paramIndex]))))/( 1+(dTemp-T0[paramIndex])*(q1[paramIndex]+q2[paramIndex]*(dTemp-T0[paramIndex]))));
// Return the result here
return dResult; }
So you spotted the tags to get bold - but not the ones for posting source code?
www.danlhenry.com/.../keil_code.png
Yes, I mean not static as a keyword, static in not changed.
Just because it's "not changed" (i.e. explicitly written to by the code), doesn't necessarily mean it will "never change", as you claimed earlier. Stuff like buffer overflow or wild pointers does happen.
See test code below.
Can't, because there's nothing to be seen: not even declarations, much less actual definitions of any of those paramater arrays.
If you expect people to help you, it's up to you to enable them to do so. A self-contained, i.e. complete, test case is just about the minimum requirement there. As is attention to details like the proper tags for posting source code.
Sorry about the missed tag. The complete code is seen below (Hopefully with the correct tags)
// Defined calculation values #define cjT0t 2.5000000E+1 #define cjV0t 9.9198279E-01 #define cjP1t 4.0716564E-02 #define cjP2t 7.1170297E-04 #define cjP3t 6.8782631E-07 #define cjP4t 4.3295061E-11 #define cjq1t 1.6458102E-02 #define cjq2t 0.0000000E+00 // array with data double T0[4] = {0, 0, 0, cjT0t}; double V0[4] = {0, 0, 0, cjV0t}; double P1[4] = {0, 0, 0, cjP1t}; double P2[4] = {0, 0, 0, cjP2t}; double P3[4] = {0, 0, 0, cjP3t}; double P4[4] = {0, 0, 0, cjP4t}; double q1[4] = {0, 0, 0, cjq1t}; double q2[4] = {0, 0, 0, cjq2t}; double q3[4] = {0, 0, 0, cjq2t}; double Calculation(double dTemp, byte paramIndex) { dTempT0 = 0.0; dq1q2Temp = 0.0; dMulti = 0.0; dDivider = 0.0; // Broken up formula for the divider dTempT0 = dTemp-T0[paramIndex]; dq1q2Temp = q1[paramIndex]+q2[paramIndex]*(dTempT0); dMulti = dTempT0*dq1q2Temp; dDivider = 1.0+dMulti; // Broken up formula dCalc1 = P4[paramIndex]*(dTempT0); dCalc2 = (P3[paramIndex]+ P4[paramIndex]*(dTempT0)); dCalc3 = (dTempT0)*((P3[paramIndex]+ P4[paramIndex]*(dTempT0))); dCalc4 = P2[paramIndex]+(dTempT0)*((P3[paramIndex]+ P4[paramIndex]*(dTempT0))); dCalc5 = (dTempT0)*(P2[paramIndex]+(dTempT0)*((P3[paramIndex]+ P4[paramIndex]* (dTempT0)))); dCalc6 = P1[paramIndex]+dCalc5; dCalc7 = (dTempT0)*(P1[paramIndex]+dCalc5); // Result with pre calculated divider dResult = V0[paramIndex] + ( (dTempT0)*(P1[paramIndex]+(dTempT0)*(P2[paramIndex]+ (dTempT0)*(P3[paramIndex]+P4[paramIndex]*(dTempT0))))/(dDivider)); // Result with all formula part pre calculated dResult1 = V0[paramIndex] + ( dCalc7/(dDivider)); // Result with formula directly calculated dResult2 = V0[paramIndex] + ( (dTemp-T0[paramIndex])*(P1[paramIndex]+(dTemp- T0[paramIndex])*(P2[paramIndex]+(dTemp-T0[paramIndex])* (P3[paramIndex]+P4[paramIndex]*(dTemp-T0[paramIndex]))))/( 1+(dTemp- T0[paramIndex])*(q1[paramIndex]+q2[paramIndex]*(dTemp-T0[paramIndex])))); // Return the result here return dResult; } // Data for calculation test double fCJTemps[] = {27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.7812, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125, 27.8125}; int nCount = 16; int nIndex = 0; // Main loop int main(void) { // Init stuff while(1) { if(nIndex >= nCount) { nIndex = 0; } double dCalculation = Calculation(fCJTemps[nIndex], 3); nIndex++; } }
.