345 lines
12 KiB
C
345 lines
12 KiB
C
|
/**************************************************************************/
|
|||
|
/*** 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 HNUMOBJ ghnoLastNum;
|
|||
|
extern BOOL bError;
|
|||
|
extern TCHAR *rgpsz[CSTRINGS];
|
|||
|
INT gnPendingError ;
|
|||
|
|
|||
|
/* Routines for more complex mathematical functions/error checking. */
|
|||
|
|
|||
|
VOID APIENTRY SciCalcFunctions (PHNUMOBJ phnoNum, DWORD wOp)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
switch (wOp)
|
|||
|
{
|
|||
|
case IDC_CHOP:
|
|||
|
if (bInv)
|
|||
|
{
|
|||
|
// fractional portion
|
|||
|
fracrat( phnoNum );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// integer portion
|
|||
|
intrat( phnoNum );
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
/* Return complement. */
|
|||
|
case IDC_COM:
|
|||
|
NumObjNot( phnoNum );
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
case IDC_PERCENT:
|
|||
|
{
|
|||
|
DECLARE_HNUMOBJ( hno );
|
|||
|
DECLARE_HNUMOBJ( hno100 );
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
NumObjAssign( &hno, ghnoLastNum );
|
|||
|
NumObjSetIntValue( &hno100, 100 );
|
|||
|
|
|||
|
divrat( &hno, hno100 );
|
|||
|
|
|||
|
NumObjDestroy( &hno100 );
|
|||
|
|
|||
|
mulrat( phnoNum, hno );
|
|||
|
|
|||
|
NumObjDestroy( &hno );
|
|||
|
}
|
|||
|
catch ( DWORD nErrCode )
|
|||
|
{
|
|||
|
if ( hno != NULL )
|
|||
|
NumObjDestroy( &hno );
|
|||
|
if ( hno100 != NULL )
|
|||
|
NumObjDestroy( &hno100 );
|
|||
|
throw nErrCode;
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
case IDC_SIN: /* Sine; normal, hyperbolic, arc, and archyperbolic */
|
|||
|
if (F_INTMATH())
|
|||
|
{
|
|||
|
MessageBeep(0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if(bInv)
|
|||
|
{
|
|||
|
if (bHyp)
|
|||
|
{
|
|||
|
asinhrat( phnoNum );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
asinanglerat( phnoNum, nDecMode );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (bHyp)
|
|||
|
{
|
|||
|
// hyperbolic sine
|
|||
|
sinhrat( phnoNum );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NumObjSin( phnoNum );
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_COS: /* Cosine, follows convention of sine function. */
|
|||
|
if (F_INTMATH())
|
|||
|
{
|
|||
|
MessageBeep(0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if(bInv)
|
|||
|
{
|
|||
|
if (bHyp)
|
|||
|
{
|
|||
|
acoshrat( phnoNum );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
acosanglerat( phnoNum, nDecMode );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (bHyp)
|
|||
|
coshrat( phnoNum );
|
|||
|
else
|
|||
|
{
|
|||
|
// cos()
|
|||
|
NumObjCos( phnoNum );
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_TAN: /* Same as sine and cosine. */
|
|||
|
if (F_INTMATH())
|
|||
|
{
|
|||
|
MessageBeep(0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if(bInv)
|
|||
|
{
|
|||
|
if (bHyp)
|
|||
|
{
|
|||
|
atanhrat( phnoNum );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
atananglerat( phnoNum, nDecMode );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (bHyp)
|
|||
|
tanhrat( phnoNum );
|
|||
|
else
|
|||
|
{
|
|||
|
// Get the answer
|
|||
|
NumObjTan( phnoNum );
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_REC: /* Reciprocal. */
|
|||
|
NumObjInvert( phnoNum );
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_SQR: /* Square and square root. */
|
|||
|
case IDC_SQRT:
|
|||
|
if(bInv || nCalc)
|
|||
|
{
|
|||
|
rootrat( phnoNum, HNO_TWO );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ratpowlong( phnoNum, 2 );
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_CUB: /* Cubing and cube root functions. */
|
|||
|
if(bInv) {
|
|||
|
DECLARE_HNUMOBJ( hno );
|
|||
|
|
|||
|
// REVIEW: if constants like 3 are going to be used repeatedly, it will be
|
|||
|
// much quicker to define them once and then keep around the definition.
|
|||
|
try
|
|||
|
{
|
|||
|
NumObjAssign( &hno, HNO_ONE );
|
|||
|
addrat( &hno, HNO_TWO );
|
|||
|
|
|||
|
rootrat( phnoNum, hno );
|
|||
|
|
|||
|
NumObjDestroy( &hno );
|
|||
|
}
|
|||
|
catch ( DWORD nErrCode )
|
|||
|
{
|
|||
|
if ( hno != NULL )
|
|||
|
NumObjDestroy( &hno );
|
|||
|
|
|||
|
throw nErrCode;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
/* Cube it, you dig? */
|
|||
|
ratpowlong( phnoNum, 3 );
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_LOG: /* Functions for common and natural log. */
|
|||
|
case IDC_LN:
|
|||
|
if(bInv)
|
|||
|
{
|
|||
|
/* Check maximum for exponentiation for 10<31> and e<>. */
|
|||
|
if (wOp==IDC_LOG) /* Do exponentiation. */
|
|||
|
NumObjAntiLog10( phnoNum ); // 10<31>.
|
|||
|
else
|
|||
|
exprat( phnoNum ); // e<>.
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// ratpak checks for valid range and throws error code if needed
|
|||
|
if (wOp==IDC_LOG)
|
|||
|
log10rat( phnoNum );
|
|||
|
else
|
|||
|
lograt( phnoNum );
|
|||
|
|
|||
|
// REVIEW: Is conversion of epsilon still needed?
|
|||
|
NumObjCvtEpsilonToZero( phnoNum );
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_FAC: /* Calculate factorial. Inverse is ineffective. */
|
|||
|
factrat( phnoNum );
|
|||
|
return;
|
|||
|
|
|||
|
case IDC_DMS:
|
|||
|
{
|
|||
|
if (F_INTMATH())
|
|||
|
{
|
|||
|
MessageBeep(0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DECLARE_HNUMOBJ(hnoMin);
|
|||
|
DECLARE_HNUMOBJ(hnoSec);
|
|||
|
DECLARE_HNUMOBJ(hnoShft);
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
NumObjSetIntValue( &hnoShft, bInv ? 100 : 60 );
|
|||
|
|
|||
|
NumObjAssign( &hnoMin, *phnoNum );
|
|||
|
intrat( phnoNum );
|
|||
|
|
|||
|
subrat( &hnoMin, *phnoNum );
|
|||
|
mulrat( &hnoMin, hnoShft );
|
|||
|
NumObjAssign( &hnoSec, hnoMin );
|
|||
|
intrat( &hnoMin );
|
|||
|
|
|||
|
subrat( &hnoSec, hnoMin );
|
|||
|
mulrat( &hnoSec, hnoShft );
|
|||
|
|
|||
|
//
|
|||
|
// *phnoNum == degrees, hnoMin == minutes, hnoSec == seconds
|
|||
|
//
|
|||
|
|
|||
|
NumObjSetIntValue( &hnoShft, bInv ? 60 : 100 );
|
|||
|
divrat( &hnoSec, hnoShft );
|
|||
|
addrat( &hnoMin, hnoSec );
|
|||
|
|
|||
|
divrat( &hnoMin, hnoShft );
|
|||
|
addrat( phnoNum, hnoMin );
|
|||
|
|
|||
|
NumObjDestroy( &hnoShft );
|
|||
|
NumObjDestroy( &hnoMin );
|
|||
|
NumObjDestroy( &hnoSec );
|
|||
|
}
|
|||
|
catch ( DWORD nErrCode )
|
|||
|
{
|
|||
|
if ( hnoShft != NULL )
|
|||
|
NumObjDestroy( &hnoShft );
|
|||
|
if ( hnoMin != NULL )
|
|||
|
NumObjDestroy( &hnoMin );
|
|||
|
if ( hnoSec != NULL )
|
|||
|
NumObjDestroy( &hnoSec );
|
|||
|
throw nErrCode;
|
|||
|
}
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
} // end switch( nOp )
|
|||
|
}
|
|||
|
catch( DWORD nErrCode )
|
|||
|
{
|
|||
|
DisplayError( nErrCode );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Routine to display error messages and set bError flag. Errors are */
|
|||
|
/* called with DisplayError (n), where n is a INT between 0 and 5. */
|
|||
|
|
|||
|
VOID APIENTRY DisplayError (INT nError)
|
|||
|
{
|
|||
|
SetDisplayText(g_hwndDlg, rgpsz[IDS_ERRORS+nError]);
|
|||
|
bError=TRUE; /* Set error flag. Only cleared with CLEAR or CENTR. */
|
|||
|
|
|||
|
/* save the pending error */
|
|||
|
gnPendingError = nError ;
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|