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;
|
||
}
|
||
|