@Terry - I think I was able to prove this was happening. First let me explain what the problem was (or at least what I think is a plausible explanation of what it was).
Why a C# executable gives different results to Excel?
Any application can set the floating point state to be whatever it requires. In fact, this is good practice so you can ensure specific precision in your application (if it matters).
When you run from a C# executable, the floating point settings used are whatever the compiler decided. However, when you run it in Excel, Excel changes the floating point settings to be whatever it requires which may be different to the executable. This is why you get a difference.
Why running within Excel may give different results each time?
Excel changes the floating point settings to whatever it needs. However, it only does this on the threads that it needs to use. So if Excel needs N threads, it will set the floating point settings on those N threads. The floating point settings on any newly spawned threads are not copied from the "master" thread. So if the process in your add-in needs M > N threads, then there are M-N threads which are spawned with different floating point settings to the N set by Excel. So now you have M threads kicking around which have two sets of different floating point settings. Because the threads which get used in parallel programming are not deterministic, you may get different results each time you run in Excel.
How I resolved it?
I resolved this by explicitly setting the floating point settings on every thread used to ensure it is always the same. I introduced the following routine. It's in C++ but you should be able to get it working in C# too.
[DllImport("msvcrt.dll")] int _controlfp(int IN_New, int IN_Mask);
void FixFPU()
{
_controlfp(_MCW_DN, _DN_SAVE);
_controlfp(_MCW_EM, _EM_INVALID);
_controlfp(_MCW_RC, _RC_CHOP);
_controlfp(_MCW_PC, _PC_53);
}
I called this routine inside the Parallel.For loop. This ensures that each thread used by the Parallel.For loop has the same floating point settings. By explicitly specifying the floating point state, you override Excel's floating point settings on those threads while your routine is running from your add-in. I also called this routine at the start of my process to ensure that the single thread used at the start is also running the same floating point settings. This ensures that any calculations done prior to getting to the Parallel.For loop are executed with the same precision as those inside the Parallel.For loop.
It's the last statement in that routine which makes the biggest difference as this sets the precision.
I hope this helps you to resolve your problem.