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
contains static double values. So they do neve change.
That conclusion would generally be wrong, since in C or C++ programs, "static" does not actually preclude changing. For that, they would have to be "const".
And what about paramIndex: is that the same, too? What's it there for, other than to actually make that formula yield different values, for different values of paramIndex?
I think he's probably just using the word in its general English sense - not meaning the C 'static' keyword ... ?
Even 'const' doesn't (necessarily) guarantee that variables will be unchangeable; eg, by errant pointers, buffer overrun, stack overflow, etc ...
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.
For a reasonably standard emedded system, it does.
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++; } }
.
To be honest, I've not spent the time trying to interpret your formula, but I've just tried pasting your code into a simple project on an LPC845 (identical core to the LPC824).
I get consistent results of:
Index:1 Val=1.105545 Index:2 Val=1.105545 Index:3 Val=1.105545 Index:4 Val=1.105545 Index:5 Val=1.105545 Index:6 Val=1.105545 Index:7 Val=1.105545 Index:8 Val=1.105545 Index:9 Val=1.106827 Index:10 Val=1.106827 Index:11 Val=1.106827 Index:12 Val=1.106827 Index:13 Val=1.106827 Index:14 Val=1.106827 Index:15 Val=1.106827 Index:16 Val=1.106827
I've tried running it multiple times in a loop, resetting the CPU, powering down/up and always get the same.
So, at the moment, my conclusion must be that you've got some sort of corruption occurring with your project configuration.
Is that the "complete code" that was exhibiting the original problem, or just the demo?
If it's just the demo, do you still see the problem in it?
LPC User wrote: "I get consistent results"
It was just part of the complete code. But I have stripped everything else away in my project, and run the code (as posted).
Here are my results
Value dResult dResult1 dResult2 Index 1 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 2 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 3 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 4 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 5 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 6 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 7 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 8 27.7812 1.105545438064 1.105545438064 1.105545438064 Index 9 27.8125 1.10671996255 1.10671996255 1.109160524578 Index 10 27.8125 1.10671996255 1.10671996255 1.107294639882 Index 11 27.8125 1.10671996255 1.10671996255 1.107294641133 Index 12 27.8125 1.10671996255 1.10671996255 1.107294639882 Index 13 27.8125 1.10671996255 1.10671996255 1.107294641133 Index 14 27.8125 1.10671996255 1.10671996255 1.109160524578 Index 15 27.8125 1.10671996255 1.10671996255 1.109160524578 Index 16 27.8125 1.10671996255 1.10671996255 1.109160524578
The dResult2 is the value with no segmented formula. It is changing every time using 27.8125 as the stimuli value. Not with the other. And is NOT the same values when I restart the program as posted earlier. Next time i run it, it can be different values.
What I also have noticed, is that the value calculated with 27.8125 is a bit of compared to my TI86 calculator. It must be 1.106827150. The result posted by LPC User using the LPC845 gives the correct value?
Why?
My project can be downloaded here: owncloud.agramkow.com/.../GeG3B6pFMVVqMRr
The result posted by LPC User using the LPC845 gives the correct value?
Are you asking if my result is correct? I don't know. As I said before, I didn't try to understand the calculation.
The value shown is the dCalculation. I didn't report the intermediate values.
Hi again,
I tried removing more and more code and it seems related to setting the CPU to low power mode.
It is related to this:
cmdData[0] = 12; cmdData[1] = PWR_LOW_CURRENT; cmdData[2] = 12; __disable_irq(); LPC_ROM_API->pPWRD->set_power(cmdData, &response); __enable_irq();
Removing this does the trick. With both the changing value and the precision
Any idea why? Because I need the low power mode.
Yes, you result are the correct ones. My is a bit of.
But it seems to be related to setting the LPC824 into low power mode.
You've only got a 256 byte stack. You're not far off that with your code and I don't know what the internal ROM routines use.
Have you tried increasing that stack size?
That's probably something you need to take to NXP, then...