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