ref #65, new formula functions: RRI, SLN and SYD

pull/2/head
xuri 3 years ago
parent 5f907b7824
commit 1df7f32cc6
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7

@ -474,6 +474,7 @@ type formulaFuncs struct {
// ROUNDUP // ROUNDUP
// ROW // ROW
// ROWS // ROWS
// RRI
// SEC // SEC
// SECH // SECH
// SHEET // SHEET
@ -481,6 +482,7 @@ type formulaFuncs struct {
// SIN // SIN
// SINH // SINH
// SKEW // SKEW
// SLN
// SMALL // SMALL
// SQRT // SQRT
// SQRTPI // SQRTPI
@ -491,6 +493,7 @@ type formulaFuncs struct {
// SUM // SUM
// SUMIF // SUMIF
// SUMSQ // SUMSQ
// SYD
// T // T
// TAN // TAN
// TANH // TANH
@ -9317,3 +9320,81 @@ func (fn *formulaFuncs) PMT(argsList *list.List) formulaArg {
func (fn *formulaFuncs) PPMT(argsList *list.List) formulaArg { func (fn *formulaFuncs) PPMT(argsList *list.List) formulaArg {
return fn.ipmt("PPMT", argsList) return fn.ipmt("PPMT", argsList)
} }
// RRI function calculates the equivalent interest rate for an investment with
// specified present value, future value and duration. The syntax of the
// function is:
//
// RRI(nper,pv,fv)
//
func (fn *formulaFuncs) RRI(argsList *list.List) formulaArg {
if argsList.Len() != 3 {
return newErrorFormulaArg(formulaErrorVALUE, "RRI requires 3 arguments")
}
nper := argsList.Front().Value.(formulaArg).ToNumber()
pv := argsList.Front().Next().Value.(formulaArg).ToNumber()
fv := argsList.Back().Value.(formulaArg).ToNumber()
if nper.Type != ArgNumber || pv.Type != ArgNumber || fv.Type != ArgNumber {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
if nper.Number <= 0 {
return newErrorFormulaArg(formulaErrorNUM, "RRI requires nper argument to be > 0")
}
if pv.Number <= 0 {
return newErrorFormulaArg(formulaErrorNUM, "RRI requires pv argument to be > 0")
}
if fv.Number < 0 {
return newErrorFormulaArg(formulaErrorNUM, "RRI requires fv argument to be >= 0")
}
return newNumberFormulaArg(math.Pow(fv.Number/pv.Number, 1/nper.Number) - 1)
}
// SLN function calculates the straight line depreciation of an asset for one
// period. The syntax of the function is:
//
// SLN(cost,salvage,life)
//
func (fn *formulaFuncs) SLN(argsList *list.List) formulaArg {
if argsList.Len() != 3 {
return newErrorFormulaArg(formulaErrorVALUE, "SLN requires 3 arguments")
}
cost := argsList.Front().Value.(formulaArg).ToNumber()
salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
life := argsList.Back().Value.(formulaArg).ToNumber()
if cost.Type != ArgNumber || salvage.Type != ArgNumber || life.Type != ArgNumber {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
if life.Number == 0 {
return newErrorFormulaArg(formulaErrorNUM, "SLN requires life argument to be > 0")
}
return newNumberFormulaArg((cost.Number - salvage.Number) / life.Number)
}
// SYD function calculates the sum-of-years' digits depreciation for a
// specified period in the lifetime of an asset. The syntax of the function
// is:
//
// SYD(cost,salvage,life,per)
//
func (fn *formulaFuncs) SYD(argsList *list.List) formulaArg {
if argsList.Len() != 4 {
return newErrorFormulaArg(formulaErrorVALUE, "SYD requires 4 arguments")
}
cost := argsList.Front().Value.(formulaArg).ToNumber()
salvage := argsList.Front().Next().Value.(formulaArg).ToNumber()
life := argsList.Back().Prev().Value.(formulaArg).ToNumber()
per := argsList.Back().Value.(formulaArg).ToNumber()
if cost.Type != ArgNumber || salvage.Type != ArgNumber || life.Type != ArgNumber || per.Type != ArgNumber {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
if life.Number <= 0 {
return newErrorFormulaArg(formulaErrorNUM, "SYD requires life argument to be > 0")
}
if per.Number <= 0 {
return newErrorFormulaArg(formulaErrorNUM, "SYD requires per argument to be > 0")
}
if per.Number > life.Number {
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
}
return newNumberFormulaArg(((cost.Number - salvage.Number) * (life.Number - per.Number + 1) * 2) / (life.Number * (life.Number + 1)))
}

@ -1323,6 +1323,13 @@ func TestCalcCellValue(t *testing.T) {
// PPMT // PPMT
"=PPMT(0.05/12,2,60,50000)": "-738.2918003208238", "=PPMT(0.05/12,2,60,50000)": "-738.2918003208238",
"=PPMT(0.035/4,2,8,0,5000,1)": "-606.1094824182949", "=PPMT(0.035/4,2,8,0,5000,1)": "-606.1094824182949",
// RRI
"=RRI(10,10000,15000)": "0.0413797439924106",
// SLN
"=SLN(10000,1000,5)": "1800",
// SYD
"=SYD(10000,1000,5,1)": "3000",
"=SYD(10000,1000,5,2)": "2400",
} }
for formula, expected := range mathCalc { for formula, expected := range mathCalc {
f := prepareCalcData(cellData) f := prepareCalcData(cellData)
@ -2516,6 +2523,22 @@ func TestCalcCellValue(t *testing.T) {
"=PPMT(0,0,0,\"\",0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax", "=PPMT(0,0,0,\"\",0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
"=PPMT(0,0,0,0,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax", "=PPMT(0,0,0,0,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
"=PPMT(0,0,0,0,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax", "=PPMT(0,0,0,0,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
// RRI
"=RRI()": "RRI requires 3 arguments",
"=RRI(\"\",\"\",\"\")": "#NUM!",
"=RRI(0,10000,15000)": "RRI requires nper argument to be > 0",
"=RRI(10,0,15000)": "RRI requires pv argument to be > 0",
"=RRI(10,10000,-1)": "RRI requires fv argument to be >= 0",
// SLN
"=SLN()": "SLN requires 3 arguments",
"=SLN(\"\",\"\",\"\")": "#NUM!",
"=SLN(10000,1000,0)": "SLN requires life argument to be > 0",
// SYD
"=SYD()": "SYD requires 4 arguments",
"=SYD(\"\",\"\",\"\",\"\")": "#NUM!",
"=SYD(10000,1000,0,1)": "SYD requires life argument to be > 0",
"=SYD(10000,1000,5,0)": "SYD requires per argument to be > 0",
"=SYD(10000,1000,1,5)": "#NUM!",
} }
for formula, expected := range mathCalcError { for formula, expected := range mathCalcError {
f := prepareCalcData(cellData) f := prepareCalcData(cellData)

Loading…
Cancel
Save