|
|
@ -55,6 +55,8 @@ const (
|
|
|
|
// displays only the leading 15 figures. In the second line, the number one
|
|
|
|
// displays only the leading 15 figures. In the second line, the number one
|
|
|
|
// is added to the fraction, and again Excel displays only 15 figures.
|
|
|
|
// is added to the fraction, and again Excel displays only 15 figures.
|
|
|
|
const numericPrecision = 1000000000000000
|
|
|
|
const numericPrecision = 1000000000000000
|
|
|
|
|
|
|
|
const maxFinancialIterations = 128
|
|
|
|
|
|
|
|
const financialPercision = 1.0e-08
|
|
|
|
|
|
|
|
|
|
|
|
// cellRef defines the structure of a cell reference.
|
|
|
|
// cellRef defines the structure of a cell reference.
|
|
|
|
type cellRef struct {
|
|
|
|
type cellRef struct {
|
|
|
@ -329,6 +331,7 @@ var tokenPriority = map[string]int{
|
|
|
|
// IMTAN
|
|
|
|
// IMTAN
|
|
|
|
// INT
|
|
|
|
// INT
|
|
|
|
// IPMT
|
|
|
|
// IPMT
|
|
|
|
|
|
|
|
// IRR
|
|
|
|
// ISBLANK
|
|
|
|
// ISBLANK
|
|
|
|
// ISERR
|
|
|
|
// ISERR
|
|
|
|
// ISERROR
|
|
|
|
// ISERROR
|
|
|
@ -359,6 +362,7 @@ var tokenPriority = map[string]int{
|
|
|
|
// MIDB
|
|
|
|
// MIDB
|
|
|
|
// MIN
|
|
|
|
// MIN
|
|
|
|
// MINA
|
|
|
|
// MINA
|
|
|
|
|
|
|
|
// MIRR
|
|
|
|
// MOD
|
|
|
|
// MOD
|
|
|
|
// MROUND
|
|
|
|
// MROUND
|
|
|
|
// MULTINOMIAL
|
|
|
|
// MULTINOMIAL
|
|
|
@ -7573,6 +7577,76 @@ func (fn *formulaFuncs) ipmt(name string, argsList *list.List) formulaArg {
|
|
|
|
return newNumberFormulaArg(principal)
|
|
|
|
return newNumberFormulaArg(principal)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// IRR function returns the Internal Rate of Return for a supplied series of
|
|
|
|
|
|
|
|
// periodic cash flows (i.e. an initial investment value and a series of net
|
|
|
|
|
|
|
|
// income values). The syntax of the function is:
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// IRR(values,[guess])
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
func (fn *formulaFuncs) IRR(argsList *list.List) formulaArg {
|
|
|
|
|
|
|
|
if argsList.Len() < 1 {
|
|
|
|
|
|
|
|
return newErrorFormulaArg(formulaErrorVALUE, "IRR requires at least 1 argument")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if argsList.Len() > 2 {
|
|
|
|
|
|
|
|
return newErrorFormulaArg(formulaErrorVALUE, "IRR allows at most 2 arguments")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
values, guess := argsList.Front().Value.(formulaArg).ToList(), newNumberFormulaArg(0.1)
|
|
|
|
|
|
|
|
if argsList.Len() > 1 {
|
|
|
|
|
|
|
|
if guess = argsList.Back().Value.(formulaArg).ToNumber(); guess.Type != ArgNumber {
|
|
|
|
|
|
|
|
return guess
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
x1, x2 := newNumberFormulaArg(0), guess
|
|
|
|
|
|
|
|
args := list.New().Init()
|
|
|
|
|
|
|
|
args.PushBack(x1)
|
|
|
|
|
|
|
|
for _, v := range values {
|
|
|
|
|
|
|
|
args.PushBack(v)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
f1 := fn.NPV(args)
|
|
|
|
|
|
|
|
args.Front().Value = x2
|
|
|
|
|
|
|
|
f2 := fn.NPV(args)
|
|
|
|
|
|
|
|
for i := 0; i < maxFinancialIterations; i++ {
|
|
|
|
|
|
|
|
if f1.Number*f2.Number < 0 {
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if math.Abs(f1.Number) < math.Abs((f2.Number)) {
|
|
|
|
|
|
|
|
x1.Number += 1.6 * (x1.Number - x2.Number)
|
|
|
|
|
|
|
|
args.Front().Value = x1
|
|
|
|
|
|
|
|
f1 = fn.NPV(args)
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
x2.Number += 1.6 * (x2.Number - x1.Number)
|
|
|
|
|
|
|
|
args.Front().Value = x2
|
|
|
|
|
|
|
|
f2 = fn.NPV(args)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if f1.Number*f2.Number > 0 {
|
|
|
|
|
|
|
|
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
args.Front().Value = x1
|
|
|
|
|
|
|
|
f := fn.NPV(args)
|
|
|
|
|
|
|
|
var rtb, dx, xMid, fMid float64
|
|
|
|
|
|
|
|
if f.Number < 0 {
|
|
|
|
|
|
|
|
rtb = x1.Number
|
|
|
|
|
|
|
|
dx = x2.Number - x1.Number
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
rtb = x2.Number
|
|
|
|
|
|
|
|
dx = x1.Number - x2.Number
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < maxFinancialIterations; i++ {
|
|
|
|
|
|
|
|
dx *= 0.5
|
|
|
|
|
|
|
|
xMid = rtb + dx
|
|
|
|
|
|
|
|
args.Front().Value = newNumberFormulaArg(xMid)
|
|
|
|
|
|
|
|
fMid = fn.NPV(args).Number
|
|
|
|
|
|
|
|
if fMid <= 0 {
|
|
|
|
|
|
|
|
rtb = xMid
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if math.Abs(fMid) < financialPercision || math.Abs(dx) < financialPercision {
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return newNumberFormulaArg(xMid)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ISPMT function calculates the interest paid during a specific period of a
|
|
|
|
// ISPMT function calculates the interest paid during a specific period of a
|
|
|
|
// loan or investment. The syntax of the function is:
|
|
|
|
// loan or investment. The syntax of the function is:
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -7609,6 +7683,41 @@ func (fn *formulaFuncs) ISPMT(argsList *list.List) formulaArg {
|
|
|
|
return newNumberFormulaArg(num)
|
|
|
|
return newNumberFormulaArg(num)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MIRR function returns the Modified Internal Rate of Return for a supplied
|
|
|
|
|
|
|
|
// series of periodic cash flows (i.e. a set of values, which includes an
|
|
|
|
|
|
|
|
// initial investment value and a series of net income values). The syntax of
|
|
|
|
|
|
|
|
// the function is:
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// MIRR(values,finance_rate,reinvest_rate)
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
func (fn *formulaFuncs) MIRR(argsList *list.List) formulaArg {
|
|
|
|
|
|
|
|
if argsList.Len() != 3 {
|
|
|
|
|
|
|
|
return newErrorFormulaArg(formulaErrorVALUE, "MIRR requires 3 arguments")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
values := argsList.Front().Value.(formulaArg).ToList()
|
|
|
|
|
|
|
|
financeRate := argsList.Front().Next().Value.(formulaArg).ToNumber()
|
|
|
|
|
|
|
|
if financeRate.Type != ArgNumber {
|
|
|
|
|
|
|
|
return financeRate
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
reinvestRate := argsList.Back().Value.(formulaArg).ToNumber()
|
|
|
|
|
|
|
|
if reinvestRate.Type != ArgNumber {
|
|
|
|
|
|
|
|
return reinvestRate
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
n, fr, rr, npvPos, npvNeg := len(values), 1+financeRate.Number, 1+reinvestRate.Number, 0.0, 0.0
|
|
|
|
|
|
|
|
for i, v := range values {
|
|
|
|
|
|
|
|
val := v.ToNumber()
|
|
|
|
|
|
|
|
if val.Number >= 0 {
|
|
|
|
|
|
|
|
npvPos += val.Number / math.Pow(float64(rr), float64(i))
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
npvNeg += val.Number / math.Pow(float64(fr), float64(i))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if npvNeg == 0 || npvPos == 0 || reinvestRate.Number <= -1 {
|
|
|
|
|
|
|
|
return newErrorFormulaArg(formulaErrorDIV, formulaErrorDIV)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return newNumberFormulaArg(math.Pow(-npvPos*math.Pow(rr, float64(n))/(npvNeg*rr), 1/(float64(n)-1)) - 1)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NOMINAL function returns the nominal interest rate for a given effective
|
|
|
|
// NOMINAL function returns the nominal interest rate for a given effective
|
|
|
|
// interest rate and number of compounding periods per year. The syntax of
|
|
|
|
// interest rate and number of compounding periods per year. The syntax of
|
|
|
|
// the function is:
|
|
|
|
// the function is:
|
|
|
|