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
		
			
				
	
	
		
			225 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* DEC	*InternalRateOfReturn(irr, flows, nflow)
 | |
|  *
 | |
|  * ARGUMENT
 | |
|  *	DEC	*irr, **flows;
 | |
|  *	int	nflow;
 | |
|  *
 | |
|  * DESCRIPTION
 | |
|  *	Calculates the internal	rate of	return of a series of cash flows.
 | |
|  *   The internal rate of return, rounded to wGMIntrPrec decimal places,
 | |
|  *   is	stored in irr.
 | |
|  *
 | |
|  * SIDE	EFFECTS
 | |
|  *	None.
 | |
|  *
 | |
|  * RETURNS
 | |
|  *	irr if successful, otherwise GM_NULL.
 | |
|  *
 | |
|  * POSSIBLE ERRORS
 | |
|  *	GM_NULLPOINTER
 | |
|  *	GM_ARGVAL
 | |
|  *
 | |
|  * AUTHOR
 | |
|  *  Jared Levy
 | |
|  *   Copyright (C) 1988-1990 Greenleaf Software	Inc.  All rights reserved.
 | |
|  *
 | |
|  * MODIFICATIONS
 | |
|  *
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include "gmsystem.h"
 | |
| static void	_NPVaux(DEC *, DEC **, int, DEC	*);
 | |
| 
 | |
| DEC	*InternalRateOfReturn(irr, flows, nflow)
 | |
| DEC	*irr, **flows;
 | |
| int	nflow;
 | |
| {
 | |
| 	mbool	wfPos, wfNeg, wfDone;
 | |
| 	int	i, j, places;
 | |
| 	DEC	dx1, *x1=&dx1, dx2, *x2=&dx2;
 | |
| 	DEC	dy1, *y1=&dy1, dy2, *y2=&dy2;
 | |
| 	DEC	dxn, *xn=&dxn, dyn, *yn=&dyn;
 | |
| 	DEC	dtemp, *temp=&dtemp, dtemp2, *temp2=&dtemp2;
 | |
| 
 | |
| 	_MacStart(GM_IRR);
 | |
| 
 | |
| 	if (nflow<2)  {
 | |
| 		_MacErr(GM_ARGVAL);
 | |
| 		_MacRet(GM_NULL);
 | |
| 	}
 | |
| 
 | |
| 	if (!flows||!irr)  {
 | |
| 		_MacErr(GM_NULLPOINTER);
 | |
| 		_MacRet(GM_NULL);
 | |
| 	}
 | |
| 
 | |
| 	/* check for null pointers, at least one pos & neg cash	flow */
 | |
| 	wfPos=FALSE;
 | |
| 	wfNeg=FALSE;
 | |
| 	for (i=0;i<nflow;i++)  {
 | |
| 		_MacInVarD(flows[i]);
 | |
| 		wfPos=wfPos||_MacIsDecP(flows[i]);
 | |
| 		wfNeg=wfNeg||_MacIsDecN(flows[i]);
 | |
| 	}
 | |
| 	if (!wfPos||!wfNeg)  {
 | |
| 		_MacErr(GM_ARGVAL);
 | |
| 		_MacRet(GM_NULL);
 | |
| 	}
 | |
| 
 | |
| 	places = wIntrPrec;
 | |
| 	if (places<0)
 | |
| 		places=0;
 | |
| 	if (places>18)
 | |
| 		places=18;
 | |
| 
 | |
| /* find	bounds */
 | |
| /*
 | |
|  * The initial 2 guesses for IRR have been changed.  The old code started
 | |
|  * with	guesses	of 2% &	2.2%, and tried	to extrapolate from there.  I
 | |
|  * have	changed	it to guess 2% and -2%.
 | |
|  */
 | |
| 	/* load	initial	guesses	*/
 | |
| 	_MacDCopy(x1, pGMIRRGuess);
 | |
| 	if (_MacIsDecZ(x1))
 | |
| 		(void) MakeDecimalFromLong(x2, 1L, 1);
 | |
| 	_MacDCopy( x2, x1 );
 | |
| 	_MacDChgs( x2 );
 | |
| 
 | |
| 	_NPVaux(y1, flows, nflow, x1);
 | |
| 	_NPVaux(y2, flows, nflow, x2);
 | |
| 
 | |
| 	/* use secant method to	find bounds */
 | |
| 	i=0;
 | |
| 	while ((!(_MacIsDecN(y1)^_MacIsDecN(y2))) && i<15)  {
 | |
| 		i++;
 | |
| 		j = CompareDecimal(y1, y2);
 | |
| 		if (j==0)  {				/* |y1|=|y2| */
 | |
| 			(void) _AddDec80Bit(x2,	x1, x2);
 | |
| 			(void) _MulDec80Bit(x2,	x2, &decPoint5);
 | |
| 			_NPVaux(y2, flows, nflow, x2);
 | |
| 		}
 | |
| 		else  {
 | |
| 			/* compute new value */
 | |
| 			(void) _SubDec80Bit(temp, x2, x1);
 | |
| 			(void) _SubDec80Bit(temp2, y2, y1);
 | |
| 			(void) _DivDec80Bit(temp, temp,	temp2);
 | |
| 			(void) _MulDec80Bit(temp, temp,	&decOnePoint6);
 | |
| 			if ((j==1)^(_MacIsDecN(y1))) {	/* |y1|>|y2| */
 | |
| 				(void) _MulDec80Bit(temp, temp,	y2);
 | |
| 				(void) _SubDec80Bit(x1,	x2, temp);
 | |
| 				_NPVaux(y1, flows, nflow, x1);
 | |
| 			}
 | |
| 			else  {				/* |y2|>|y1| */
 | |
| 				(void) _MulDec80Bit(temp, temp,	y1);
 | |
| 				(void) _SubDec80Bit(x2,	x1, temp);
 | |
| 				_NPVaux(y2, flows, nflow, x2);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* find	bounds,	method 2 */
 | |
| 	if (i>=15)  {
 | |
| 		/* load	initial	guesses	*/
 | |
| 		_MacDCopy(x1, pGMIRRGuess);
 | |
| 		if (_MacIsDecZ(x1))
 | |
| 			MakeDecimalFromLong(x2,	1L, 1);
 | |
| 		else  {
 | |
| 			_MacDCopy(x2, x1);
 | |
| 			x2->dc.id++;
 | |
| 			(void) _SubDec80Bit(x2,	x1, x2);
 | |
| 		}
 | |
| 		_NPVaux(y1, flows, nflow, x1);
 | |
| 		_NPVaux(y2, flows, nflow, x2);
 | |
| 
 | |
| 		while (!(_MacIsDecN(y1)^_MacIsDecN(y2)))  {
 | |
| 			j = CompareDecimal(y1, y2);
 | |
| 			if ((j==1)^(_MacIsDecN(y1))) {	/* |y1|>|y2| */
 | |
| 				_AddDec80Bit(temp, x2, x2);
 | |
| 				_SubDec80Bit(x2, temp, x1);
 | |
| 				if ((CompareDecimal(x2,	&decHundred) ==	1)
 | |
| 				 || (CompareDecimal(x2,	&decMinus50) ==	-1)) {
 | |
| 					 _MacErr(GM_ARGVAL);
 | |
| 					 _MacRet(GM_NULL);
 | |
| 					 }
 | |
| 				_NPVaux(y2, flows, nflow, x2);
 | |
| 				 }
 | |
| 			else  {				/* |y2|>|y1| */
 | |
| 				_AddDec80Bit(temp, x1, x1);
 | |
| 				_SubDec80Bit(x1, temp, x2);
 | |
| 				if ((CompareDecimal(x1,	&decHundred) ==	1)
 | |
| 				 || (CompareDecimal(x1,	&decMinus50) ==	-1)) {
 | |
| 					 _MacErr(GM_ARGVAL);
 | |
| 					 _MacRet(GM_NULL);
 | |
| 				 }
 | |
| 				_NPVaux(y1, flows, nflow, x1);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| /* If this stage is reached, bounds have been found */
 | |
| /* Now use bisection to	find the IRR between those bounds */
 | |
| 	wfDone=FALSE;
 | |
| 	while (!wfDone)	 {
 | |
| /* calculate new position */
 | |
| 		(void) _AddDec80Bit(xn,	x2, x1);
 | |
| 	       _HalveUnsArr(xn->dc.sl, 5);
 | |
| 	       if (xn->dc.id !=	places)
 | |
| 		       _ScaleDec80Bit(xn, xn, places);
 | |
| 
 | |
| /* calculate corresponding y */
 | |
| 		_NPVaux(yn, flows, nflow, xn);
 | |
| 
 | |
| /* check for approximate or exact zero */
 | |
| 		if (_MacIsDecZ(yn))  {
 | |
| 			_MacDCopy(irr,xn);
 | |
| 			_MacRet(irr);
 | |
| 		}
 | |
| 
 | |
| /* 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);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	_MacDCopy(irr, xn);
 | |
| 	_MacRet(xn);
 | |
| }
 | |
| 
 | |
| static void	_NPVaux(net, flows, nflow, intr)
 | |
| DEC	*net, **flows, *intr;
 | |
| int	nflow;
 | |
| {
 | |
| 	int	i;
 | |
| 	DEC	dtemp, *temp=&dtemp, dooopi, *ooopi=&dooopi;
 | |
| 	DEC	dpow, *pow=&dpow;
 | |
| 
 | |
| 	_MacDZero(net);
 | |
| 	_MacDCopy(temp,	intr);
 | |
| 	if (temp->dc.id	<= GM_MAXID-2)
 | |
| 		temp->dc.id+=2;
 | |
| 	else
 | |
| 		(void) _DivUnsArrByPwrOf10(temp->dc.sl,	5, 2);
 | |
| 	(void) _AddDec80Bit(temp, temp,	&decOne);
 | |
| 	(void) _DivDec80Bit(ooopi, &decOne, temp);
 | |
| 
 | |
| 	_MacDCopy(pow, (&decOne));
 | |
| 
 | |
| 	for (i=0;i<nflow;i++)  {
 | |
| 		(void) _MulDec80Bit(temp, flows[i], pow);
 | |
| 		(void) _AddDec80Bit(net, net, temp);
 | |
| 		(void) _MulDec80Bit(pow, pow, ooopi);
 | |
| 	}
 | |
| 
 | |
| }
 |