Files correlati : Ricompilazione Demo : [ ] Commento : Aggiunti i sorgenti per Greenleaf Math Library (gfm.dll) git-svn-id: svn://10.65.10.50/trunk@10079 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			299 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* DEC	*_InterestAux(fun, intper, fractper, intr, pv, pmt, fv,	begend)
 | |
|  *
 | |
|  * ARGUMENT
 | |
|  *	int	fun, intper, begend;
 | |
|  *	DEC	*fractper, *intr, *pv, *pmt, *fv;
 | |
|  *
 | |
|  * DESCRIPTION
 | |
|  *	Given four variables involved in compound interest, solves for the
 | |
|  *  interest.  The variables are the number of periods nper, the percentage
 | |
|  *  interest rate per period intr, the present value pv, the periodic payment
 | |
|  *  pmt, and the future	value fv.  begend specifies whether payments take
 | |
|  *  place at the beginning or the end of each month.
 | |
|  *	This auxillary function	does the work of CompoundInterest,
 | |
|  *  CompoundInterestSimple, and	CompoundInterestCompound for calculating intr.
 | |
|  *
 | |
|  * SIDE	EFFECTS
 | |
|  *	Changes	value of intr.
 | |
|  *
 | |
|  * RETURNS
 | |
|  *	In case	of success, intr is returned.
 | |
|  *  If an error	occurs,	GM_NULL	is returned.
 | |
|  *
 | |
|  * POSSIBLE ERRORS
 | |
|  *	GM_NULLPOINTER
 | |
|  *	GM_ARGVAL
 | |
|  *
 | |
|  *
 | |
|  *
 | |
|  * AUTHOR
 | |
|  *  Jared Levy
 | |
|  *   Copyright (C) 1988-1990 Greenleaf Software	Inc.  All rights reserved.
 | |
|  *
 | |
|  * ALGORITHM
 | |
|  *	Solve the following formula for	the unknown variable:
 | |
|  *  0=pv*alpha + (1+intr*begend)*pmt*[1-(1+intr)^-int(nper)]/intr +
 | |
|  *	 fv*(1+intr)^-int(nper)
 | |
|  *  where alpha=1 for no odd period,
 | |
|  *	  alpha=1+intr*frac(nper) for an odd period with simple	interest
 | |
|  *	  alpha=(1+intr)^frac(nper) for	an odd period with compound interest
 | |
|  *
 | |
|  *  The	equation can be	solved in closed form for any variable except intr,
 | |
|  *  which requires numerical methods.
 | |
|  *  The	variables used by this routine have the	following meanings:
 | |
|  *	fun:   1 if called by ComoundInterest, 2 if by CompoundInterestSimple,
 | |
|  *		3 if by	CompoundInterestCompound, and 0	if by AdvancePayment
 | |
|  *	intper:	integer	part of	nper
 | |
|  *	fractper: fractional part of nper (if fun==2 or	fun==3)
 | |
|  *	intr:  interest	rate per period
 | |
|  *	pv:    present value
 | |
|  *	pmt:   period payment
 | |
|  *	fv:    future value (balloon payment)
 | |
|  *	begend:	GM_BEGIN if payments at	beginning of period, GM_END if at end
 | |
|  *		(or if fun==0, number of advanced payments ad)
 | |
|  *	temp1, temp2: temporary	DEC's
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include "gm.h"
 | |
| #include "gmsystem.h"
 | |
| static	void	zcom(DEC *, int, int, DEC *, DEC *, DEC	*, DEC *, DEC *, int);
 | |
| 
 | |
| DEC	*_InterestAux(fun, intper, fractper, intr, pv, pmt, fv,	begend)
 | |
| int	fun, intper, begend;
 | |
| DEC	*fractper, *intr, *pv, *pmt, *fv;
 | |
| {
 | |
| 	int	i, places, ad;
 | |
| 	mbool	wfDone;
 | |
| 	DEC	dx1, *x1=&dx1, dx2, *x2=&dx2, dpx1, *px1=&dpx1;
 | |
| 	DEC	dpx2, *px2=&dpx2, dy1, *y1=&dy1, dy2, *y2=&dy2;
 | |
| 	DEC	dy0, *y0=&dy0, dxn, *xn=&dxn, dyn, *yn=&dyn;
 | |
| 	DEC	djunk, *junk=&djunk;
 | |
| 	DEC	dtemp1,	*temp1=&dtemp1,	dtemp2,	*temp2=&dtemp2;
 | |
| 
 | |
| /* Can't have zero payments */
 | |
| 	if (intper==0)	{
 | |
| 		_MacErr(GM_ARGVAL);
 | |
| 		return(GM_NULL);
 | |
| 	}
 | |
| 
 | |
| 	ad = begend;
 | |
| 
 | |
| /* add advance payments	to pv */
 | |
| 	if (fun==0)  {
 | |
| 		(void) ConvLongToDecimal(junk, (long) ad);
 | |
| 		(void) _MulDec80Bit(junk, pmt, junk);
 | |
| 		(void) _AddDec80Bit(junk, junk,	pv);
 | |
| 		pv = junk;
 | |
| 	}
 | |
| 
 | |
| /* Check that there's a	positive & a negative value among pv, pmt, fv */
 | |
| 	if (!(_MacIsDecP(pv)||_MacIsDecP(pmt)||_MacIsDecP(fv)))	{
 | |
| 		_MacErr(GM_ARGVAL);
 | |
| 		return(GM_NULL);
 | |
| 	}
 | |
| 
 | |
| 	if (!(_MacIsDecN(pv)||_MacIsDecN(pmt)||_MacIsDecN(fv)))	 {
 | |
| 		_MacErr(GM_ARGVAL);
 | |
| 		return(GM_NULL);
 | |
| 	}
 | |
| 
 | |
| /* if pmt==0, solve quickly */
 | |
| /* 0 = pv + fv * (1 + i/100) ^ n ==>
 | |
|    i = (exp[ ln	(fv / pv) / n] - 1) * 100 */
 | |
| 	if (_MacIsDecZ(pmt)&&fun<=1)  {
 | |
| 		(void) _DivDec80Bit(temp1, fv, pv);
 | |
| 		_MacDChgs(temp1);
 | |
| 		(void) _LnDec80Bit(temp1, temp1);
 | |
| 		(void) ConvLongToDecimal(temp2,	(long) intper);
 | |
| 		(void) _DivDec80Bit(temp1, temp1, temp2);
 | |
| 		(void) _ExpDec80Bit(temp1, temp1);
 | |
| 		(void) _SubDec80Bit(temp1, temp1, &decOne);
 | |
| 		temp1->dc.id-=2;
 | |
| 		(void) _ScaleDec80Bit(intr, temp1, wIntrPrec);
 | |
| 		(void) _Sq5UnsTo4Uns(intr);
 | |
| 		return(intr);
 | |
| 	}
 | |
| 
 | |
| /* find	bounds for intr	*/
 | |
| /* initial bounds: 0 and 1 (percent) */
 | |
| 	_MacDZero(x1);
 | |
| 	_MacDCopy(x2, (&decOne));
 | |
| 	zcom(y1, fun, intper, fractper,	x1, pv,	pmt, fv, begend);
 | |
| 	zcom(y2, fun, intper, fractper,	x2, pv,	pmt, fv, begend);
 | |
| 	if (_MacIsDecZ(y1))  {
 | |
| 		_MacDCopy(intr,y1);
 | |
| 		return(intr);
 | |
| 	}
 | |
| 	if (_MacIsDecZ(y2))  {
 | |
| 		_MacDCopy(intr,y2);
 | |
| 		return(intr);
 | |
| 	}
 | |
| 	_MacDCopy(y0,y1);
 | |
| 	_MacDCopy(px1, x2);
 | |
| 	_MacDCopy(px2, x1);
 | |
| 
 | |
| /* expanded bounds until zcom has different signs at bounds to find zero */
 | |
| 	i=0;
 | |
| 	while (!_MacIsDecN(y1)^_MacIsDecN(y2))	{
 | |
| /* change boundary with	smaller	absolute value */
 | |
| 		if ((CompareDecimal(x1,x2)==1)^_MacIsDecN(y1)) {
 | |
| /* set x2 = 2 *	x2 */
 | |
| 			_MacDCopy(px2,x2);
 | |
| 			_AddDec80Bit(x2,x2,x2);
 | |
| 			zcom(y2, fun, intper, fractper,x2,pv,pmt, fv, begend);
 | |
| 			if (_MacIsDecZ(y2))  {
 | |
| 				_MacDCopy(intr,x2);
 | |
| 				return(intr);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		else  {
 | |
| /* if x1==0, set x1 = 10%, otherwise x1	= (old x1 + -100%) / 2 */
 | |
| 			_MacDCopy(px1,x1);
 | |
| 			if (_MacIsDecZ(x1))
 | |
| 				(void) ConvLongToDecimal(x1, 10L);
 | |
| 			else  {
 | |
| 				(void) _AddDec80Bit(x1,x1,&decMinusHundred);
 | |
| 				(void) _MulDec80Bit(x1,x1,&decPoint5);
 | |
| 			}
 | |
| 			zcom(y1, fun, intper, fractper,x1,pv,pmt, fv, begend);
 | |
| 			if (_MacIsDecZ(y1))  {
 | |
| 				_MacDCopy(intr,x1);
 | |
| 				return(intr);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| /* maximum of 19 expansions */
 | |
| 		i++;
 | |
| 		if (i>19)  {
 | |
| 			_MacErr(GM_ARGVAL);
 | |
| 			return(GM_NULL);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	places=wIntrPrec;
 | |
| 	if (places<GM_MINID)
 | |
| 		places=GM_MINID;
 | |
| 	if (places>GM_MAXID)
 | |
| 		places=GM_MAXID;
 | |
| 
 | |
| 	(void) _ScaleDec80Bit(x1,x1,places);
 | |
| 	(void) _ScaleDec80Bit(x2,x2,places);
 | |
| 
 | |
| 	if (CompareDecimal(x1,&decMinusHundred)==0)  {
 | |
| 		_MacDCopy(intr,x2);
 | |
| 		return(intr);
 | |
| 	}
 | |
| 
 | |
| /* Restrict range to smaller region with different signs */
 | |
| 	if (_MacIsDecN(y0)^_MacIsDecN(y2))
 | |
| 		_MacDCopy(x1,px2);
 | |
| 	else
 | |
| 		_MacDCopy(x2,px1);
 | |
| 
 | |
| 
 | |
| /* Find	root by	bisection (Numerical Recipes in	C, p. 263) */
 | |
| 	wfDone=FALSE;
 | |
| 	while (!wfDone)	 {
 | |
| /* calculate new position */
 | |
| 		(void) _AddDec80Bit(xn,	x2, x1);
 | |
| 		       _HalveUnsArr(xn->dc.sl, 5);
 | |
| /*		(void) _SubDec80Bit(temp1, x2, x1);
 | |
| 		(void) _SubDec80Bit(temp2, y2, y1);
 | |
| 		(void) _DivDec80Bit(temp1, temp1, temp2);
 | |
| 		(void) _MulDec80Bit(temp1, temp1, y1);
 | |
| 		(void) _SubDec80Bit(xn,	x1, temp1);	*/
 | |
| 
 | |
| /* calculate corresponding y */
 | |
| 		zcom(yn, fun, intper, fractper,	xn, pv,	pmt, fv, begend);
 | |
| 
 | |
| /* check for approximate or exact zero */
 | |
| 		if (_MacIsDecZ(yn))  {
 | |
| 			_MacDCopy(intr,xn);
 | |
| 			return(intr);
 | |
| 		}
 | |
| 
 | |
| /* adjust appropriate boundary */
 | |
| 		if (_MacIsDecN(y1)^_MacIsDecN(yn))  {
 | |
| 			wfDone=(CompareDecimal(x2,xn)==0);
 | |
| 			_MacDCopy(x2,xn);
 | |
| 			_MacDCopy(y2,yn);
 | |
| 		}
 | |
| 		else  {
 | |
| 			wfDone=(CompareDecimal(x1,xn)==0);
 | |
| 			_MacDCopy(x1,xn);
 | |
| 			_MacDCopy(y1,yn);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	(void) _Sq5UnsTo4Uns(xn);
 | |
| 	_MacDCopy(intr,xn);
 | |
| 	return(intr);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* calculate function which must be zeroed to solved for intr */
 | |
| static void	zcom(y,	fun, intper, fractper, intr, pv, pmt, fv, begend)
 | |
| int	fun, intper, begend;
 | |
| DEC	*y, *fractper, *intr, *pv, *pmt, *fv;
 | |
| {
 | |
| 	int	ad;
 | |
| 	DEC	dopi, *opi=&dopi, dopitmn, *opitmn=&dopitmn;
 | |
| 	DEC	dtemp2,	*temp2=&dtemp2,	dopitmna, *opitmna=&dopitmna;
 | |
| 	DEC	dnintr,	*nintr=&dnintr;
 | |
| 
 | |
| 	ad=begend;
 | |
| 
 | |
| 	_MacDCopy(nintr, intr);
 | |
| 	if (intr->dc.id<=GM_IMAXID-2)
 | |
| 		nintr->dc.id+=2;
 | |
| 	else
 | |
| 		(void) _MulDec80Bit(nintr,intr,&decPoint01);
 | |
| 
 | |
| 	(void) _AddDec80Bit(opi, &decOne, nintr);
 | |
| 	(void) _IntPwrDec80Bit(opitmn, opi, -intper);
 | |
| 	if (fun==0)
 | |
| 		(void) _IntPwrDec80Bit(opitmna,	opi, -(intper-ad));
 | |
| 
 | |
| 	(void) _MulDec80Bit(y, fv, opitmn);
 | |
| 
 | |
| 	if (!_MacIsDecZ(pv))  {
 | |
| 		if (fun<=1)
 | |
| 			_MacDCopy(temp2, pv);
 | |
| 		if (fun==2)  {
 | |
| 			(void) _MulDec80Bit(temp2, nintr, fractper);
 | |
| 			(void) _AddDec80Bit(temp2, temp2, &decOne);
 | |
| 			(void) _MulDec80Bit(temp2, temp2, pv);
 | |
| 		}
 | |
| 		if (fun==3)  {
 | |
| 			(void) PowerDecimal(temp2, opi,	fractper);
 | |
| 			(void) _MulDec80Bit(temp2, temp2, pv);
 | |
| 		}
 | |
| 		(void) _AddDec80Bit(y, y, temp2);
 | |
| 	}
 | |
| 
 | |
| 	if (_MacIsDecZ(nintr))	{
 | |
| 		if (fun!=0)
 | |
| 			(void) ConvLongToDecimal(temp2,	(long) intper);
 | |
| 		else
 | |
| 			(void) ConvLongToDecimal(temp2,	(long) (intper-ad));
 | |
| 		(void) _MulDec80Bit(temp2, temp2, pmt);
 | |
| 	}
 | |
| 	else  {
 | |
| 		if (fun!=0)
 | |
| 			(void) _SubDec80Bit(temp2, &decOne, opitmn);
 | |
| 		else
 | |
| 			(void) _SubDec80Bit(temp2, &decOne, opitmna);
 | |
| 		(void) _DivDec80Bit(temp2, temp2, nintr);
 | |
| 		(void) _MulDec80Bit(temp2, temp2, pmt);
 | |
| 		if (begend==GM_BEGIN&&fun!=0)
 | |
| 			(void) _MulDec80Bit(temp2, temp2, opi);
 | |
| 	}
 | |
| 	(void) _AddDec80Bit(y, y, temp2);
 | |
| 
 | |
| 
 | |
| }
 |