mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
478 lines
16 KiB
478 lines
16 KiB
/**************************************************************************/
|
|
/*** SCICALC Scientific Calculator for Windows 3.00.12 ***/
|
|
/*** By Kraig Brockschmidt, Microsoft Co-op, Contractor, 1988-1989 ***/
|
|
/*** (c)1989 Microsoft Corporation. All Rights Reserved. ***/
|
|
/*** ***/
|
|
/*** scifunc.c ***/
|
|
/*** ***/
|
|
/*** Functions contained: ***/
|
|
/*** SciCalcFunctions--do sin, cos, tan, com, log, ln, rec, fac, etc.***/
|
|
/*** DisplayError--Error display driver. ***/
|
|
/*** ***/
|
|
/*** Functions called: ***/
|
|
/*** SciCalcFunctions call DisplayError. ***/
|
|
/*** ***/
|
|
/*** Last modification. Fri 05-Jan-1990. ***/
|
|
/*** ***/
|
|
/*** -by- Amit Chatterjee. [amitc] 05-Jan-1990. ***/
|
|
/*** Calc did not have a floating point exception signal handler. This ***/
|
|
/*** would cause CALC to be forced to exit on a FP exception as that's ***/
|
|
/*** the default. ***/
|
|
/*** The signal handler is defined in here, in SCIMAIN.C we hook the ***/
|
|
/*** the signal. ***/
|
|
/*** ***/
|
|
/*** -by- Amit Chatterjee. [amitc] 14-Dec-1989 ***/
|
|
/*** The REC function will not depend on the bInv flag. It used to ret ***/
|
|
/*** a random number when the bInv flag was set. ***/
|
|
/*** ***/
|
|
/*** -by- Amit Chatterjee. [amitc] 08-Dec-1989 ***/
|
|
/*** Did a minor bug fix. The EnableToggles routine now sets the focus ***/
|
|
/*** back to the main window before disabling HEX,DEC etc.. Without this***/
|
|
/*** the window with the focus would get disable and cause MOVE to not ***/
|
|
/*** work right. ***/
|
|
/*** ***/
|
|
/**************************************************************************/
|
|
|
|
#include "scicalc.h"
|
|
#include "float.h"
|
|
|
|
extern double fCleanUpMod(double a, double c);
|
|
|
|
extern double fpNum, fpLastNum, fpTrigType[3];
|
|
extern BOOL bInv, bHyp, bError;
|
|
extern HWND hgWnd;
|
|
extern INT nCalc, nTrig;
|
|
extern TCHAR *rgpsz[CSTRINGS];
|
|
INT nPendingError ;
|
|
|
|
|
|
/* Routines for more complex mathematical functions/error checking. */
|
|
|
|
VOID APIENTRY SciCalcFunctions (DWORD wOp)
|
|
{
|
|
LONG lIndex, lTemp;
|
|
double fpSave, fpSec, fpMin, fpSign=1.0, fpTemp, fpX;
|
|
|
|
if (fpNum < 0.0)
|
|
fpSign=-1.0;
|
|
|
|
switch (wOp)
|
|
{
|
|
case CHOP:
|
|
/* Return either integer or fractional portion of fpNum */
|
|
fpTemp=CalcModF(fRoundForDisplay(fpNum), &fpMin);
|
|
|
|
if (bInv)
|
|
fpNum= fCleanUpMod(fabs(fpNum), fpTemp);
|
|
else
|
|
fpNum=fpMin;
|
|
return;
|
|
|
|
/* Return complement. */
|
|
case COM:
|
|
if (fabs(fpNum) > TOPLONG)
|
|
DisplayError (SCERR_DOMAIN);
|
|
else
|
|
#if defined(_MIPS_) || defined(_PPC_)
|
|
{
|
|
|
|
//
|
|
// Temporary untill the mips compiler correctly supports
|
|
// double to unsigned int.
|
|
//
|
|
|
|
DWORD z;
|
|
|
|
if (fpNum < 0) {
|
|
z = FDtoUL(-fpNum);
|
|
z = NegateUL(z);
|
|
} else {
|
|
z = FDtoUL(fpNum);
|
|
}
|
|
|
|
fpNum=(double) ~z;
|
|
|
|
}
|
|
#else
|
|
fpNum=(double) ~(LONG) fpNum;
|
|
#endif
|
|
return;
|
|
|
|
case PERCENT:
|
|
fpNum *=(fpLastNum/100);
|
|
return;
|
|
|
|
case SIN: /* Sine; normal, hyperbolic, arc, and archyperbolic */
|
|
if(bInv)
|
|
{
|
|
if (bHyp)
|
|
/* Following is formula for archyperbolic sine. All */
|
|
/* real numbers are legal. */
|
|
fpNum=log(fpNum+sqrt(1.0+fpNum*fpNum));
|
|
else
|
|
// asin() return in radians. range -pi/2 to pi/2
|
|
fpNum = asin(fpNum) * fpTrigType[nTrig];
|
|
}
|
|
else
|
|
{
|
|
if (bHyp)
|
|
{
|
|
// hyperbolic sin()
|
|
fpNum = sinh(fpNum);
|
|
}
|
|
else
|
|
{
|
|
// sin()
|
|
// special case a few values for the press
|
|
|
|
double fpPress = fabs(fpNum);
|
|
|
|
if (nTrig == 0 &&
|
|
(fpPress == 180.0 ||
|
|
fpPress == 360.0 ||
|
|
fpPress == 540.0 ||
|
|
fpPress == 720.0))
|
|
{
|
|
fpNum = 0.0;
|
|
return;
|
|
}
|
|
|
|
if (nTrig == 1 &&
|
|
(fpPress == PI_VAL ||
|
|
fpPress == 2.0 * PI_VAL ||
|
|
fpPress == 3.0 * PI_VAL ||
|
|
fpPress == 4.0 * PI_VAL))
|
|
{
|
|
fpNum = 0.0;
|
|
return;
|
|
}
|
|
|
|
fpNum = sin(fpNum / fpTrigType[nTrig]);
|
|
|
|
// Win31 hack because cos(PI/2) doesn't equal 0.0
|
|
|
|
if (fabs(fpNum) < 1.0e-15)
|
|
fpNum = 0.0;
|
|
}
|
|
}
|
|
return;
|
|
|
|
case COS: /* Cosine, follows convention of sine function. */
|
|
if(bInv)
|
|
{
|
|
if (bHyp)
|
|
{
|
|
if (fpNum <1.0) /* Valid range for archyperbolic. */
|
|
{
|
|
DisplayError (SCERR_DOMAIN);
|
|
return;
|
|
}
|
|
/* Following is archyperbolic cosine formula. All */
|
|
/* positive values >=1.0 are valid. */
|
|
fpNum=log(fpNum+sqrt(-1.0+fpNum*fpNum));
|
|
}
|
|
else
|
|
// acos() return in radians. range -pi/2 to pi/2
|
|
fpNum = acos(fpNum) * fpTrigType[nTrig];
|
|
}
|
|
else
|
|
{
|
|
if (bHyp)
|
|
fpNum = cosh(fpNum);
|
|
else
|
|
{
|
|
// cos()
|
|
// special case a few values for the press
|
|
|
|
double fpPress = fabs(fpNum);
|
|
|
|
if (nTrig == 0 &&
|
|
(fpPress == 90.0 ||
|
|
fpPress == 270.0 ||
|
|
fpPress == 450.0 ||
|
|
fpPress == 630.0))
|
|
{
|
|
fpNum = 0.0;
|
|
return;
|
|
}
|
|
|
|
if (nTrig == 1 &&
|
|
(fpPress == 0.5 * PI_VAL ||
|
|
fpPress == 1.5 * PI_VAL ||
|
|
fpPress == 2.5 * PI_VAL ||
|
|
fpPress == 3.5 * PI_VAL))
|
|
{
|
|
fpNum = 0.0;
|
|
return;
|
|
}
|
|
|
|
fpNum = cos(fpNum / fpTrigType[nTrig]);
|
|
|
|
// Win31 hack because cos(PI/2) doesn't equal 0.0
|
|
|
|
if (fabs(fpNum) < 1.0e-15)
|
|
fpNum = 0.0;
|
|
}
|
|
}
|
|
return;
|
|
|
|
case TAN: /* Same as sine and cosine. */
|
|
if(bInv)
|
|
{
|
|
if (bHyp)
|
|
{
|
|
if (fabs(fpNum) >= 1.0)
|
|
{
|
|
DisplayError (SCERR_DOMAIN);
|
|
return;
|
|
}
|
|
/* Formula for archyperbolic tangent. Valid range is */
|
|
/* -1 to +1. */
|
|
fpNum=.5*log((1.0+fpNum)/(1.0-fpNum));
|
|
}
|
|
else
|
|
fpNum=atan(fpNum)*fpTrigType[nTrig];
|
|
}
|
|
else
|
|
if (bHyp)
|
|
fpNum=tanh(fpNum);
|
|
else
|
|
{
|
|
// tan()
|
|
// special case a few values for the press
|
|
|
|
double fpPress = fabs(fpNum);
|
|
|
|
if (nTrig == 0 &&
|
|
(fpPress == 180.0 ||
|
|
fpPress == 360.0 ||
|
|
fpPress == 540.0 ||
|
|
fpPress == 720.0))
|
|
{
|
|
fpNum = 0.0;
|
|
return;
|
|
}
|
|
|
|
if (nTrig == 1 &&
|
|
(fpPress == PI_VAL ||
|
|
fpPress == 2.0 * PI_VAL ||
|
|
fpPress == 3.0 * PI_VAL ||
|
|
fpPress == 4.0 * PI_VAL))
|
|
{
|
|
fpNum = 0.0;
|
|
return;
|
|
}
|
|
|
|
// The conversion from degrees to radians is so
|
|
// poor tan(3PI/2) == error but tan(270) != error.
|
|
// Special case a few more values...
|
|
|
|
if (nTrig == 0 &&
|
|
(fpPress == 90.0 ||
|
|
fpPress == 270.0 ||
|
|
fpPress == 450.0 ||
|
|
fpPress == 630.0))
|
|
{
|
|
fpNum = tan(PI_VAL / 2.0);
|
|
}
|
|
else
|
|
{
|
|
fpNum = tan(fpNum / fpTrigType[nTrig]);
|
|
}
|
|
|
|
if (fabs(fpNum) > 1e+15)
|
|
DisplayError (SCERR_UNDEFINED);
|
|
}
|
|
return;
|
|
|
|
case REC: /* Reciprocal. */
|
|
if (fpNum==0.0) /* x/0 is illegal. */
|
|
DisplayError(SCERR_DIVIDEZERO);
|
|
else
|
|
fpNum=1/fpNum;
|
|
|
|
return;
|
|
|
|
case SQR: /* Square and square root. */
|
|
if(bInv || nCalc)
|
|
{
|
|
if (fpNum < 0.0)
|
|
DisplayError(SCERR_UNDEFINED);
|
|
else
|
|
fpNum=sqrt(fpNum);
|
|
}
|
|
else
|
|
{
|
|
/* Check if number is too big. */
|
|
if (fabs(fpNum) > 1.0e+154)
|
|
DisplayError (SCERR_OVERFLOW);
|
|
else
|
|
fpNum *=fpNum; /* Square that puppy. */
|
|
}
|
|
return;
|
|
|
|
case CUB: /* Cubing and cube root functions. */
|
|
if(bInv)
|
|
fpNum=fpSign * pow(fabs(fpNum), 1.0/3.0);
|
|
else
|
|
{
|
|
/* Check upper limit. */
|
|
if ( fabs(fpNum) > (1.0e+102))
|
|
DisplayError (SCERR_OVERFLOW);
|
|
else
|
|
fpNum = fpNum*fpNum*fpNum; /* Cube it, you dig? */
|
|
}
|
|
return;
|
|
|
|
case LOG: /* Functions for common and natural log. */
|
|
case LN:
|
|
if(bInv)
|
|
{
|
|
/* Check maximum for exponentiation for 10ü and eü. */
|
|
if (wOp==LOG) /* Do exponentiation. */
|
|
fpNum=pow(10.0, fpNum); /* 10ü. */
|
|
else
|
|
fpNum=pow(MATHE, fpNum); /* eü. */
|
|
}
|
|
else
|
|
{
|
|
/* Check for illegal logarithm domain. */
|
|
if (fpNum<=0.0)
|
|
DisplayError(SCERR_UNDEFINED);
|
|
else
|
|
{
|
|
if (wOp==LOG)
|
|
fpNum=log10(fpNum);
|
|
else
|
|
fpNum=log(fpNum);
|
|
}
|
|
}
|
|
return;
|
|
|
|
case FAC: /* Calculate factorial. Inverse is ineffective. */
|
|
/* Check for negative. */
|
|
if (fmod(fpNum, 1.0)!=0.0 || fpNum < 0.0)
|
|
{
|
|
DisplayError (SCERR_DOMAIN);
|
|
return;
|
|
}
|
|
|
|
|
|
/* Check for maximum limit. */
|
|
if (fpNum > 170.0)
|
|
DisplayError (SCERR_OVERFLOW);
|
|
else
|
|
{
|
|
lTemp=(LONG) fpNum; /* Convert to a interger number. */
|
|
fpNum=1.0;
|
|
for (lIndex=2; lIndex<=lTemp; lIndex++)
|
|
fpNum *= (double) lIndex;
|
|
}
|
|
return;
|
|
|
|
case DMS:
|
|
/* Degrees <-> degrees/minutes/seconds conversions. */
|
|
fpTemp = CalcModF(fpSign*fpNum, &fpSave);
|
|
|
|
/* Multiplies fpTemp *100 with bInv TRUE, otherwise *60 */
|
|
fpX=60.0+((bInv) ? (40.0) : (0.0));
|
|
fpSec = CalcModF((fpTemp*fpX), &fpMin);
|
|
|
|
if (fpSec > 1.0-(1.0e-11))
|
|
{
|
|
fpSec=0.0;
|
|
fpMin+=1.0;
|
|
}
|
|
|
|
if (bInv)
|
|
/* Convert to degrees format. */
|
|
fpNum =fpSign*(fpSave + (fpMin/60.0) + (fpSec/36));
|
|
else
|
|
/* Convert to degree-minutes-seconds format. */
|
|
fpNum=fpSign*(fpSave+(fpMin/100.0)+(fpSec*.006));
|
|
|
|
break;
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* Routine to display error messages and set bError flag. Errors are */
|
|
/* called with DisplayError (n), where n is a INT between 0 and 4. */
|
|
|
|
VOID APIENTRY DisplayError (INT nError)
|
|
{
|
|
SetDlgItemText(hgWnd, DISPLAY+nCalc, rgpsz[IDS_ERRORS+nError]);
|
|
bError=TRUE; /* Set error flag. Only cleared with CLEAR or CENTR. */
|
|
|
|
/* save the pending error */
|
|
nPendingError = nError ;
|
|
|
|
/* Don't wanna no o' dem RIP0x0007 thingamabobs. */
|
|
if (nCalc==0)
|
|
EnableToggles (FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* Routine to handle general math errors coming from the math library. */
|
|
/* Frees app from checking domains on sines, logs, etc. */
|
|
|
|
INT _CRTAPI1 matherr(x)
|
|
struct _exception *x;
|
|
{
|
|
INT nErr=x->type;
|
|
|
|
if (nErr==DOMAIN || nErr==OVERFLOW || nErr==UNDERFLOW)
|
|
DisplayError (nErr);
|
|
else
|
|
DisplayError (SCERR_UNDEFINED); /* General error. */
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Routine to handle floating point exceptions coming from the math library */
|
|
|
|
VOID FAR cdecl SignalHandler ( iType, iCode)
|
|
|
|
INT iType, iCode ;
|
|
|
|
{
|
|
if (iCode == FPE_ZERODIVIDE)
|
|
{
|
|
DisplayError (SCERR_DIVIDEZERO) ;
|
|
return ;
|
|
}
|
|
|
|
if (iCode == FPE_OVERFLOW)
|
|
{
|
|
DisplayError (SCERR_OVERFLOW) ;
|
|
return ;
|
|
}
|
|
|
|
if (iCode == FPE_UNDERFLOW)
|
|
{
|
|
DisplayError (SCERR_UNDERFLOW) ;
|
|
return ;
|
|
}
|
|
|
|
DisplayError (SCERR_UNDEFINED) ;
|
|
}
|
|
|
|
|
|
VOID APIENTRY EnableToggles(BOOL bEnable)
|
|
{
|
|
INT nx;
|
|
|
|
/* first set the focus back to the main window to ensure that we
|
|
do not disbale a window with the focus */
|
|
SetFocus (hgWnd) ;
|
|
|
|
for (nx=BIN; nx<=GRAD; nx++)
|
|
EnableWindow(GetDlgItem(hgWnd, nx), bEnable);
|
|
|
|
return;
|
|
}
|