/* DEC	*ModifiedIRR(irr, flows, nflow,	intr, safe)
 *
 * ARGUMENT
 *	DEC	*irr, **flows, *intr, *safe;
 *	int	nflow;
 *
 * DESCRIPTION
 *	Calculates the modified	int. rate of return of a series	of cash	flows.
 *   The nflow cash flows in the array flows are invested at interest
 *   rate intr for positive cash flows and borrows at interest rate safe
 *   for negative cash flows.
 *	The modified internal rate of return is	calculated and 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 "gm.h"
#include "gmsystem.h"

DEC	*ModifiedIRR(irr, flows, nflow,	intr, safe)
DEC	*irr, **flows, *intr, *safe;
int	nflow;
{
	int	i;
	mbool	wfNeg, wfPos;
	DEC	dtemp, *temp=&dtemp, dooopi, *ooopi=&dooopi;
	DEC	dpow, *pow=&dpow, dopi,	*opi=&dopi;
	DEC	dnpvn, *npvn=&dnpvn, dnfvp, *nfvp=&dnfvp;
	DEC	*p;

	_MacStart(GM_MIRR);

	if (nflow<2)  {
		_MacErr(GM_ARGVAL);
		_MacRet(GM_NULL);
	}

	_MacInVarD(intr);
	_MacInVarD(safe);
	if (!flows)  {
		_MacErr(GM_NULLPOINTER);
		_MacRet(GM_NULL);
	}
	_MacOutVarD(irr);
	/* check for null pointers, at least one pos & neg cash	flow */
	wfPos=FALSE;
	wfNeg=FALSE;
	for (i=0;i<nflow;i++)  {
		p = flows[i];
		_MacInVarD(p);
		wfPos=wfPos||_MacIsDecP(p);
		wfNeg=wfNeg||_MacIsDecN(p);
	}

	if (!wfPos||!wfNeg)  {
		_MacErr(GM_ARGVAL);
		_MacRet(GM_NULL);
	}

	if ((CompareDecimal(intr,&decMinusHundred)!=1)
		||(CompareDecimal(safe,&decMinusHundred)!=1))  {
		_MacErr(GM_ARGVAL);
		_MacRet(GM_NULL);
	}

	/* calculate npv of negative values at safe rate */
	_MacDZero(npvn);

	_MacDCopy(temp,	safe);
	temp->dc.id+=2;
	(void) _AddDec80Bit(temp, temp,	&decOne);
	(void) _DivDec80Bit(ooopi, &decOne, temp);

	_MacDCopy(pow, (&decOne));

	for (i=0;i<nflow;i++)  {
		if (_MacIsDecN(flows[i]))  {
			(void) _MulDec80Bit(temp, flows[i], pow);
			(void) _AddDec80Bit(npvn, npvn,	temp);
		}
		(void) _MulDec80Bit(pow, pow, ooopi);
	}

	/* calculate nfv of positive values at intr */
	_MacDZero(nfvp);

	_MacDCopy(temp,	intr);
	temp->dc.id+=2;
	(void) _AddDec80Bit(opi, temp, &decOne);

	_MacDCopy(pow, (&decOne));

	for (i=nflow-1;i>=0;i--)  {
		if (_MacIsDecP(flows[i]))  {
		(void) _MulDec80Bit(temp, flows[i], pow);
		(void) _AddDec80Bit(nfvp, nfvp,	temp);
		}
		(void) _MulDec80Bit(pow, pow, opi);
	}

/* calculate modified internal rate of return */
	_MacDChgs(npvn);
	(void) _DivDec80Bit(temp, nfvp,	npvn);
	(void) _LnDec80Bit(temp, temp);
	(void) ConvLongToDecimal(pow, (long) (nflow-1));
	(void) _DivDec80Bit(temp, temp,	pow);
	(void) _ExpDec80Bit(temp, temp);
	(void) _SubDec80Bit(temp, temp,	&decOne);
	if (temp->dc.id>=2)
		temp->dc.id -=2;
	else  {
		ConvLongToDecimal(pow, 100L);
		(void) _MulDec80Bit(temp, temp,	pow);
	}

	(void) _Sq5UnsTo4Uns(temp);
	_MacDCopy(irr,temp);
	_MacRet(irr);
}