View Single Post
  #20   Report Post  
Posted to microsoft.public.excel,microsoft.public.excel.programming
Martin Brown Martin Brown is offline
external usenet poster
 
Posts: 230
Default Excel and the Math Coprocessor for DLLs

On 27/03/2012 01:37, Lynn McGuire wrote:
On 3/22/2012 5:57 PM, joeu2004 wrote:
"Lynn McGuire" wrote:
My DLL is written in 700K lines of Fortran, C and C++
code. But that is all built at compile and link time.


Not necessarily. In some architectures, a "late optimization phase" is
invoked when the DLL is loaded and linked to an application.
This supports a single binary DLL that can be used on a variety of
architectures.

That is what I was alluding to earlier.

However, it's a moot point. I suspect we have established that the key
factor is _PC_53 v. _PC_64 mode.

I am still awaiting the results of your trying _PC_53 mode. But I
believe my explanation of your results with _PC_64 mode most likely
point _PC_53 mode as the solution.


I tried _PC_53. Did not help.


You must have done it wrong then, or something else is afoot.

When I try it with a fairly trivial but incredibly ugly toy code to
force each possible state of the x87 I get the following output.

// toy87.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "float.h"

double testit(int tag1, int tag2)
{
double chptst;
double divtwo;

const double top = 4195835.0;
const double bottom = 3145727.0;
_control87( tag1+tag2, _MCW_PC+_MCW_RC);

divtwo = top / bottom;
chptst = (divtwo * bottom) - top ;
return chptst;
}


int _tmain(int argc, _TCHAR* argv[])
{
for (int prec = _PC_64; prec<=_PC_24; prec += _PC_53)
for (int round = _RC_NEAR; round <= _RC_CHOP; round += _RC_DOWN)
printf("testit(%i,%i) = %e\n", prec/_PC_53, round/_RC_DOWN,
testit(prec,round));
return 0;
}

*NB* If I allow the optimiser any freedom at all it compiles to fldz

Here is the output cycling though all rounding modes of each precision:

_64_
testit(0,0) = 2.851266e-010
testit(0,1) = -4.138201e-010
testit(0,2) = 2.851266e-010
testit(0,3) = -4.138201e-010

_53_
testit(1,0) = 0.000000e+000
testit(1,1) = -9.313226e-010
testit(1,2) = 9.313226e-010
testit(1,3) = -9.313226e-010

_24_
testit(2,0) = 0.000000e+000
testit(2,1) = -5.000000e-001
testit(2,2) = 5.000000e-001
testit(2,3) = -5.000000e-001

My guess would be that you have not forced the numeric CPU into the
right state. Round to nearest gives exactly 0.0 for both 32bit and 64bit
floating point but for full 80bit hardware precision it gives an "error"
in the 54th bit. The example was constructed to trigger a rare iteration
fault in a particular CPU series on FP divide ages ago.

--
Regards,
Martin Brown