C++ Question logging a variable changes the result... impossible to understand

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,664
Reaction score
115
Points
78
Hi all,

I'm facing something here that I'm not capable to understand and therefore to avoid.

The new algorithm I developed for gravity turn evaluation works quite fine, but only if I write the variables to the log at the end of every loop...

in particular this:
Code:
 while((t0<500)&&(psi0<80*RAD)){ 

			double grel= mu/((rt+y0)*(rt+y0))-(vel*vel/(rt+y0));
		 	double n=GetProperNforCGTE(t0);
			absacc=n*g0;
			hacc=absacc*sin(psi0);
			vacc=absacc*cos(psi0)-grel;
			x=x0+hvel*deltaT+0.5*hacc*deltaT*deltaT;
			y=y0+vvel*deltaT+0.5*vacc*deltaT*deltaT;
			hvel+=hacc*deltaT;
			vvel+=vacc*deltaT;
			vel=sqrt(hvel*hvel+vvel*vvel);
			t0+=deltaT;
			deltax=x-x0;
			deltay=y-y0;
			x0=x;
			y0=y;
			
			v0=vel;
                        modspost=sqrt(deltax*deltax+deltay*deltay);
			normx=deltax/modspost;
			normy=deltay/modspost;
			psi=0.5*PI-atan2(normy,normx);
			if(psi>psi0){ 
				psi0=psi;
			}


		 if(y0>altsteps[3]){return true;}
	 }

doesn't work, while this:
Code:
 while((t0<500)&&(psi0<80*RAD)){ 
	 
			double grel= mu/((rt+y0)*(rt+y0))-(vel*vel/(rt+y0));
		 	double n=GetProperNforCGTE(t0);
			absacc=n*g0;
			hacc=absacc*sin(psi0);
			vacc=absacc*cos(psi0)-grel;
			x=x0+hvel*deltaT+0.5*hacc*deltaT*deltaT;
			y=y0+vvel*deltaT+0.5*vacc*deltaT*deltaT;
			hvel+=hacc*deltaT;
			vvel+=vacc*deltaT;
			vel=sqrt(hvel*hvel+vvel*vvel);
			t0+=deltaT;
			deltax=x-x0;
			deltay=y-y0;
			x0=x;
			y0=y;
			
			v0=vel;
                        modspost=sqrt(deltax*deltax+deltay*deltay);
			normx=deltax/modspost;
			normy=deltay/modspost;
			psi=0.5*PI-atan2(normy,normx);
			if(psi>psi0){ 
				psi0=psi;
			}
		
                [color="red"][B][U]sprintf(logbuff,"%.3f",vel);[/U]
		[U]oapiWriteLog(logbuff);[/U][/B][/color]

		 if(y0>altsteps[3]){return true;}
	 }

works perfectly.... how can this be possible???? how can I avoid it?? I already tried to change the name of vel but doesn't change.... I can't understand the meaning of this...:compbash:

Thanks in advance for any help!:sos:

Fred
 
works perfectly.... how can this be possible???? how can I avoid it??

Can you provide a code snippet of the lines where you declared the two variables (vel and logBuff), plus the three lines above and below them?

I can imagine sprintf-ing to logBuff is messing with vel, because you declared logBuff as a too small string buffer (for example forgetting the terminating \0 character, a string with 4 characters text needs a buffer of at least 5 characters size to also contain the terminator) and the output overwrites a part of vel.

"%.3f" means you have at least 5 visible characters and your buffer needs to be at least 6 characters long. According to the typical magnitudes of velocities on Orbiter, you could easily need about 10 characters buffer (5 digits, dot, 3 digits, \0)
 
logbuff length is 4096:
Code:
#define MAXLEN 4096

...

char logbuff[MAXLEN];

and about vel is declared just before the while cycle:
Code:
	 double hvel,vvel,vel,absacc,hacc,vacc,modspost,normx,normy;
		hvel=0;
		vvel=v0;
		deltaT=1;
                vel=0;
	 while((t0<500)&&(psi0<80*RAD)){ 
		 
			double grel= mu/((rt+y0)*(rt+y0))-(vel*vel/(rt+y0));
		 	double n=GetProperNforCGTE(t0);
			absacc=n*g0;
			hacc=absacc*sin(psi0);
			vacc=absacc*cos(psi0)-grel;
			x=x0+hvel*deltaT+0.5*hacc*deltaT*deltaT;
			y=y0+vvel*deltaT+0.5*vacc*deltaT*deltaT;
			hvel+=hacc*deltaT;
			vvel+=vacc*deltaT;
	
			vel=sqrt(hvel*hvel+vvel*vvel);
			t0+=deltaT;
			deltax=x-x0;
			deltay=y-y0;
			x0=x;
			y0=y;
			
			v0=vel;
                        modspost=sqrt(deltax*deltax+deltay*deltay);
			normx=deltax/modspost;
			normy=deltay/modspost;
			psi=0.5*PI-atan2(normy,normx);
			if(psi>psi0){ 
				psi0=psi;
			}

		
		
		sprintf(logbuff,"%.3f",vel);
		oapiWriteLog(logbuff);


	

		 if(y0>altsteps[3]){return true;}
	 }

what seems absurd to me is that the cycle changes its result if I log vel or if I don't :hmm:. I think that even if logbuff was used unproperly, the value of vel should be kept.

To be totally clear what it's not working is not that the value is printed wrongly, I can see the result of the cycle in the MFD and if I log vel then the result of the calculation is correct, if I don't log it the result is wrong... that's incredibly strange to me...
 
That really makes no sense... unless y0 or altsteps[3] get manipulated somewhere.
 
This smells of Undefined Behavior, i.e. the problem is most likely hidden somewhere else, due to manipulation of memory, you shouldn't have access to. It's generally advised to use STL instead of bare arrays / pointers to reduce such risk.
 
This smells of Undefined Behavior, i.e. the problem is most likely hidden somewhere else, due to manipulation of memory, you shouldn't have access to. It's generally advised to use STL instead of bare arrays / pointers to reduce such risk.

Exactly. Though STL alone does also not prevent you from shooting into your own foot with C++. (If you don't mentally walk with at least one wooden leg, you have not understood C++ yet.)
 
Exactly. Though STL alone does also not prevent you from shooting into your own foot with C++. (If you don't mentally walk with at least one wooden leg, you have not understood C++ yet.)
Naah. C++'s STL shoots off your entire leg. ;) (but looking at the parenthesis, you already have one wooden leg as well)
 
1. Define "does not work".

2. Is this supposed to be a multithreaded code? If so, the behavior would be understandable.
 
I changed the initialization of vel to vel=v0 (which is calculated before) instead of vel=0 and now it works fine... looks like it was an initialization issue, even though it remains a bit of a mistery to me...

thanks all for the replies!
 
That still doesn't make sense. If v0 is zero at the time of assignment, the change shouldn't have any effect, If it isn't zero, then there is no reason why writing to the log file would fix it.

So you may have masked the problem now, but I don't think it is fixed.

I assume you did run your code through a debugger and inspected all the values as they were computed to see where the problem pops up?
 
I checked every step again.

I am capable to replicate this curious thing only if I do not initialize the variable vel. If I take out vel=0 or vel=v0 from the code I have again the "log effect", it's like logging it makes the software aware of the variable somehow...

If I initialize it then the effect is gone and the loop works fine both if I log it or if I don't.

:shrug:
 
The declarations of the following variables might be helpful:
t0, psi0 and psi

Is there any particular reason that they are nowhere near the function?
 
I am capable to replicate this curious thing only if I do not initialize the variable vel.

{...}

If I initialize it then the effect is gone and the loop works fine both if I log it or if I don't.

But `vel` needs to be initialized before the loop since it's used in calculations (vel*vel) before another value is assigned to it.
 
If I initialize it then the effect is gone and the loop works fine both if I log it or if I don't.

Sorry, didn't see this before, you ninja'd me.
As orb said, if you don't initialise vel, then its value is undefined. I.E. it could be anything, so the very first line of your calculation will return a wrong result already.
But in the code you posted, vel is initialised, so... does that code work or not? For that matter, what exactly doesn't work?
 
yep, absolutely.

I keep finding curious that if I do not initialize the variable, but I log it then the loop works anyway.

logging it should not make any change, just show the value, but in this case it looks like it works as an initialization.
 
Rule 1: *Never* use uninitialized variables
Rule 2: If you do not obey to rule 1, *unexpected* behavior *will* bite you!

The difference between "logging" code present or not present might result in a completely
different memory layout at compile time; which might put whatever value at a memory location, the variables are placed.
On your specific code:
When you've declared the variables inside a (function-)scope -like you did-, these will be located on the stack, which contains "rubbish" whatever any previously called function might have returned or being fed with...
Sometimes this remains (rubbish) might be zeros, which could make your code work as expected. But still this is undefined behavior!

So simply initializing *all* variables is *always* better!

---------- Post added at 00:33 ---------- Previous post was at 00:26 ----------

--- addendum ---
This is just what I think could have happened. It might not be true in this case ;)
But the rules are still good practice.
 
Rule 1: *Never* use uninitialized variables
Actually it does make sense if you know what you're doing and you don't ignore compiler warnings. Consider this:
PHP:
bool conditionMain;
if (cond1)
{
   conditionMain = true;
}
else
{
  if (cond2)
  {
      conditionMain = false;
  }
  // don't try to read conditionMain here or face UB
}
The above code will issue a compilation warning about the bool possibly being not initialized. While this won't:
PHP:
bool conditionMain;
if (cond1)
{
   conditionMain = true;
}
else
{
  if (cond2)
  {
     conditionMain = false;
  }
  else
  {
    conditionMain = true;
  }
}
So this mechanism serves as an automatic checker whether all of the logic paths lead to a conclusion. However it's done better in Java, which wouldn't even compile the first code for the same reason.
 
Last edited:
However it's done better in Java, which wouldn't even compile the first code for the same reason.

Actually it would compile, but it would usually issue an "uninitialized variable" warning. Java implicitly initializes all variables with null or 0, which can still be causing unexpected behaviour. Its better to initialize, even if its 0.

But like any good compiler, you can make javac treat warnings like errors.
 
Actually it does make sense if you know what you're doing and you don't ignore compiler warnings. Consider this:
[...]snip[...]
When I wrote : "*Never* use uninitialized variables" I did not mean that
you have to initialize it at instantiation/definition.
You can assign values later on, but that's not what I meant with "use";
Your example would just mean an (late) assignment.

Anyway doing this is OK, too of course:
PHP:
void doSomething (int condition)
{
  int foo;
  switch (condition) {
    case 0: foo = 1; break;
    case 2: foo = 10; break;
    case 4: foo = 100; break;
    default: foo = 0; break;
  }
  // Now it's surely save to _use_ 'foo' (not only on the
  // left of the assignment operator [=] ;) )
}

But getting into the habit of initializing them always is always save!

PHP:
void doSomething (int condition)
{
  int foo = 0; // this is _always_ defined behavior!
  switch (condition) {
    case 0: foo = 1; break;
    case 2: foo = 10; break;
    case 4: foo = 100; break;
    default: foo = 0; break;
  }
  // ...
}
 
Back
Top