windows-nt/Source/XPSP1/NT/shell/osshell/accesory/calc/scimath.c
2020-09-26 16:20:57 +08:00

227 lines
6.3 KiB
C

#include <windows.h>
#include <stdlib.h>
#include "scicalc.h"
#include "unifunc.h"
#include "..\ratpak\debug.h"
/**************************************************************************\
* *
* *
* *
* # # ##### *
* # # # # # *
* # # # # # # # *
* # ### ### # # *
* # # ### # # # ### # # ### ##### # ### ### ### *
* # ## # # # ## # # # # # # ## # # # *
* # # # # # # # # # ##### # # ##### # *
* # # # # # # # # # # # # # # ## *
* # # # # # # # # # ### # # ### ### ## *
* *
* *
* Infinte Precision Production Version *
* *
\**************************************************************************/
//
// RETAIL version of NUMOBJ math that uses Infinite Precision
//
// History
//
// 16-Nov-1996 JonPa Wrote it
// whenever-97 ToddB Rewrote it using improved ratpak model
//
/*****************************************************************\
*
* Generic Math Package support routines and variables
*
* History:
* 01-Dec-1996 JonPa Wrote them
* whenever-97 ToddB Rewrote them
*
\*****************************************************************/
//
// Worker for NumObjRecalcConstants
//
// Returns the nearest power of two
//
int QuickLog2( int iNum )
{
int iRes = 0;
// while first digit is a zero
while ( !(iNum & 1) )
{
iRes++;
iNum >>= 1;
}
// if our number isn't a perfect square
if ( iNum = iNum >> 1 )
{
// find the largest digit
while ( iNum = iNum >> 1 )
++iRes;
// and then add two
iRes += 2;
}
return iRes;
}
////////////////////////////////////////////////////////////////////////
//
// UpdateMaxIntDigits
//
// determine the maximum number of digits needed for the current precision,
// word size, and base. This number is conservative towards the small side
// such that there may be some extra bits left over. The number of extra
// bits is returned. For example, base 8 requires 3 bits per digit. A word
// size of 32 bits allows for 10 digits with a remainder of two bits. Bases
// that require variable numnber of bits (non-power-of-two bases) are approximated
// by the next highest power-of-two base (again, to be conservative and gaurentee
// there will be no over flow verse the current word size for numbers entered).
// Base 10 is a special case and always uses the base 10 precision (nPrecision).
void UpdateMaxIntDigits()
{
extern int gcIntDigits;
int iRemainderBits;
if ( nRadix == 10 )
{
gcIntDigits = nPrecision;
iRemainderBits = 0;
}
else
{
int log2;
log2 = QuickLog2( nRadix );
ASSERT( 0 != log2 ); // same as ASSERT( nRadix != 1 )
gcIntDigits = dwWordBitWidth / log2;
iRemainderBits = dwWordBitWidth % log2;
}
}
void BaseOrPrecisionChanged( void )
{
extern LONG dwWordBitWidth;
extern int gcIntDigits;
UpdateMaxIntDigits();
if ( 10 == nRadix )
{
// to prevent unwanted rounded digits from showing up in the
// gcIntDigits + 1 spot during non-integer mode we don't want
// to add the extra 1 that we ortherwise add
ChangeConstants( nRadix, gcIntDigits );
}
else
{
ChangeConstants( nRadix, gcIntDigits+1 );
}
}
/*****************************************************************\
*
* Unary functions
*
* History:
* 01-Dec-1996 JonPa Wrote them
* whenever-97 ToddB Rewrote them
*
\*****************************************************************/
void NumObjInvert( PHNUMOBJ phno ) {
DECLARE_HNUMOBJ( hno );
NumObjAssign( &hno, HNO_ONE );
divrat( &hno, *phno );
NumObjAssign( phno, hno );
NumObjDestroy( &hno );
}
void NumObjAntiLog10( PHNUMOBJ phno ) {
DECLARE_HNUMOBJ( hno );
NumObjSetIntValue( &hno, 10 );
powrat( &hno, *phno );
NumObjAssign( phno, hno );
NumObjDestroy( &hno );
}
void NumObjNot( PHNUMOBJ phno )
{
if ( nRadix == 10 )
{
intrat( phno );
addrat( phno, HNO_ONE );
NumObjNegate( phno );
}
else
{
ASSERT( (nHexMode >= 0) && (nHexMode <= 3) );
ASSERT( phno );
ASSERT( *phno );
ASSERT( g_ahnoChopNumbers[ nHexMode ] );
xorrat( phno, g_ahnoChopNumbers[ nHexMode ] );
}
}
void NumObjSin( PHNUMOBJ phno )
{
ASSERT(( nDecMode == ANGLE_DEG ) || ( nDecMode == ANGLE_RAD ) || ( nDecMode == ANGLE_GRAD ));
sinanglerat( (PRAT *)phno, nDecMode );
NumObjCvtEpsilonToZero( phno );
}
void NumObjCos( PHNUMOBJ phno )
{
ASSERT(( nDecMode == ANGLE_DEG ) || ( nDecMode == ANGLE_RAD ) || ( nDecMode == ANGLE_GRAD ));
cosanglerat( (PRAT *)phno, nDecMode );
NumObjCvtEpsilonToZero( phno );
}
void NumObjTan( PHNUMOBJ phno )
{
ASSERT(( nDecMode == ANGLE_DEG ) || ( nDecMode == ANGLE_RAD ) || ( nDecMode == ANGLE_GRAD ));
tananglerat( (PRAT *)phno, nDecMode );
NumObjCvtEpsilonToZero( phno );
}
/******************************************************************\
*
* Number format conversion routines
*
* History:
* 06-Dec-1996 JonPa wrote them
\******************************************************************/
void NumObjSetIntValue( PHNUMOBJ phnol, LONG i ) {
PRAT pr = NULL;
pr = longtorat( i );
NumObjAssign( phnol, (HNUMOBJ)pr );
destroyrat(pr);
}
void NumObjGetSzValue( LPTSTR *ppszNum, HNUMOBJ hnoNum, INT nRadix, NUMOBJ_FMT fmt ) {
LPTSTR psz;
psz = putrat( &hnoNum, nRadix, fmt );
if (psz != NULL) {
if (*ppszNum != NULL) {
NumObjFreeMem( *ppszNum );
}
*ppszNum = psz;
}
}