forked from p30928647/excelize
#65 fn: IPMT, PMT and PPMT
This commit is contained in:
parent
737b7839a2
commit
a8197485b5
134
calc.go
134
calc.go
|
@ -319,6 +319,7 @@ var tokenPriority = map[string]int{
|
|||
// IMSUM
|
||||
// IMTAN
|
||||
// INT
|
||||
// IPMT
|
||||
// ISBLANK
|
||||
// ISERR
|
||||
// ISERROR
|
||||
|
@ -374,9 +375,11 @@ var tokenPriority = map[string]int{
|
|||
// PERMUT
|
||||
// PERMUTATIONA
|
||||
// PI
|
||||
// PMT
|
||||
// POISSON.DIST
|
||||
// POISSON
|
||||
// POWER
|
||||
// PPMT
|
||||
// PRODUCT
|
||||
// PROPER
|
||||
// QUARTILE
|
||||
|
@ -7156,3 +7159,134 @@ func (fn *formulaFuncs) ENCODEURL(argsList *list.List) formulaArg {
|
|||
token := argsList.Front().Value.(formulaArg).Value()
|
||||
return newStringFormulaArg(strings.Replace(url.QueryEscape(token), "+", "%20", -1))
|
||||
}
|
||||
|
||||
// Financial Functions
|
||||
|
||||
// IPMT function calculates the interest payment, during a specific period of a
|
||||
// loan or investment that is paid in constant periodic payments, with a
|
||||
// constant interest rate. The syntax of the function is:
|
||||
//
|
||||
// IPMT(rate,per,nper,pv,[fv],[type])
|
||||
//
|
||||
func (fn *formulaFuncs) IPMT(argsList *list.List) formulaArg {
|
||||
return fn.ipmt("IPMT", argsList)
|
||||
}
|
||||
|
||||
// ipmt is an implementation of the formula function IPMT and PPMT.
|
||||
func (fn *formulaFuncs) ipmt(name string, argsList *list.List) formulaArg {
|
||||
if argsList.Len() < 4 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires at least 4 arguments", name))
|
||||
}
|
||||
if argsList.Len() > 6 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s allows at most 6 arguments", name))
|
||||
}
|
||||
rate := argsList.Front().Value.(formulaArg).ToNumber()
|
||||
if rate.Type != ArgNumber {
|
||||
return rate
|
||||
}
|
||||
per := argsList.Front().Next().Value.(formulaArg).ToNumber()
|
||||
if per.Type != ArgNumber {
|
||||
return per
|
||||
}
|
||||
nper := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if nper.Type != ArgNumber {
|
||||
return nper
|
||||
}
|
||||
pv := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if pv.Type != ArgNumber {
|
||||
return pv
|
||||
}
|
||||
fv, typ := newNumberFormulaArg(0), newNumberFormulaArg(0)
|
||||
if argsList.Len() >= 5 {
|
||||
if fv = argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
|
||||
return fv
|
||||
}
|
||||
}
|
||||
if argsList.Len() == 6 {
|
||||
if typ = argsList.Back().Value.(formulaArg).ToNumber(); typ.Type != ArgNumber {
|
||||
return typ
|
||||
}
|
||||
}
|
||||
if typ.Number != 0 && typ.Number != 1 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
if per.Number <= 0 || per.Number > nper.Number {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
args := list.New().Init()
|
||||
args.PushBack(rate)
|
||||
args.PushBack(nper)
|
||||
args.PushBack(pv)
|
||||
args.PushBack(fv)
|
||||
args.PushBack(typ)
|
||||
pmt, capital, interest, principal := fn.PMT(args), pv.Number, 0.0, 0.0
|
||||
for i := 1; i <= int(per.Number); i++ {
|
||||
if typ.Number != 0 && i == 1 {
|
||||
interest = 0
|
||||
} else {
|
||||
interest = -capital * rate.Number
|
||||
}
|
||||
principal = pmt.Number - interest
|
||||
capital += principal
|
||||
}
|
||||
if name == "IPMT" {
|
||||
return newNumberFormulaArg(interest)
|
||||
}
|
||||
return newNumberFormulaArg(principal)
|
||||
}
|
||||
|
||||
// PMT function calculates the constant periodic payment required to pay off
|
||||
// (or partially pay off) a loan or investment, with a constant interest
|
||||
// rate, over a specified period. The syntax of the function is:
|
||||
//
|
||||
// PMT(rate,nper,pv,[fv],[type])
|
||||
//
|
||||
func (fn *formulaFuncs) PMT(argsList *list.List) formulaArg {
|
||||
if argsList.Len() < 3 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "PMT requires at least 3 arguments")
|
||||
}
|
||||
if argsList.Len() > 5 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "PMT allows at most 5 arguments")
|
||||
}
|
||||
rate := argsList.Front().Value.(formulaArg).ToNumber()
|
||||
if rate.Type != ArgNumber {
|
||||
return rate
|
||||
}
|
||||
nper := argsList.Front().Next().Value.(formulaArg).ToNumber()
|
||||
if nper.Type != ArgNumber {
|
||||
return nper
|
||||
}
|
||||
pv := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if pv.Type != ArgNumber {
|
||||
return pv
|
||||
}
|
||||
fv, typ := newNumberFormulaArg(0), newNumberFormulaArg(0)
|
||||
if argsList.Len() >= 4 {
|
||||
if fv = argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber(); fv.Type != ArgNumber {
|
||||
return fv
|
||||
}
|
||||
}
|
||||
if argsList.Len() == 5 {
|
||||
if typ = argsList.Back().Value.(formulaArg).ToNumber(); typ.Type != ArgNumber {
|
||||
return typ
|
||||
}
|
||||
}
|
||||
if typ.Number != 0 && typ.Number != 1 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
if rate.Number != 0 {
|
||||
p := (-fv.Number - pv.Number*math.Pow((1+rate.Number), nper.Number)) / (1 + rate.Number*typ.Number) / ((math.Pow((1+rate.Number), nper.Number) - 1) / rate.Number)
|
||||
return newNumberFormulaArg(p)
|
||||
}
|
||||
return newNumberFormulaArg((-pv.Number - fv.Number) / nper.Number)
|
||||
}
|
||||
|
||||
// PPMT function calculates the payment on the principal, during a specific
|
||||
// period of a loan or investment that is paid in constant periodic payments,
|
||||
// with a constant interest rate. The syntax of the function is:
|
||||
//
|
||||
// PPMT(rate,per,nper,pv,[fv],[type])
|
||||
//
|
||||
func (fn *formulaFuncs) PPMT(argsList *list.List) formulaArg {
|
||||
return fn.ipmt("PPMT", argsList)
|
||||
}
|
||||
|
|
44
calc_test.go
44
calc_test.go
|
@ -1132,6 +1132,16 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// Web Functions
|
||||
// ENCODEURL
|
||||
"=ENCODEURL(\"https://xuri.me/excelize/en/?q=Save As\")": "https%3A%2F%2Fxuri.me%2Fexcelize%2Fen%2F%3Fq%3DSave%20As",
|
||||
// Financial Functions
|
||||
// IPMT
|
||||
"=IPMT(0.05/12,2,60,50000)": "-205.26988187971995",
|
||||
"=IPMT(0.035/4,2,8,0,5000,1)": "5.257455237829077",
|
||||
// PMT
|
||||
"=PMT(0,8,0,5000,1)": "-625",
|
||||
"=PMT(0.035/4,8,0,5000,1)": "-600.8520271804658",
|
||||
// PPMT
|
||||
"=PPMT(0.05/12,2,60,50000)": "-738.2918003208238",
|
||||
"=PPMT(0.035/4,2,8,0,5000,1)": "-606.1094824182949",
|
||||
}
|
||||
for formula, expected := range mathCalc {
|
||||
f := prepareCalcData(cellData)
|
||||
|
@ -2019,6 +2029,40 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// Web Functions
|
||||
// ENCODEURL
|
||||
"=ENCODEURL()": "ENCODEURL requires 1 argument",
|
||||
// Financial Functions
|
||||
// IPMT
|
||||
"=IPMT()": "IPMT requires at least 4 arguments",
|
||||
"=IPMT(0,0,0,0,0,0,0)": "IPMT allows at most 6 arguments",
|
||||
"=IPMT(0,0,0,0,0,2)": "#N/A",
|
||||
"=IPMT(0,-1,0,0,0,0)": "#N/A",
|
||||
"=IPMT(0,1,0,0,0,0)": "#N/A",
|
||||
"=IPMT(\"\",0,0,0,0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=IPMT(0,\"\",0,0,0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=IPMT(0,0,\"\",0,0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=IPMT(0,0,0,\"\",0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=IPMT(0,0,0,0,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=IPMT(0,0,0,0,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
// PMT
|
||||
"=PMT()": "PMT requires at least 3 arguments",
|
||||
"=PMT(0,0,0,0,0,0)": "PMT allows at most 5 arguments",
|
||||
"=PMT(0,0,0,0,2)": "#N/A",
|
||||
"=PMT(\"\",0,0,0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=PMT(0,\"\",0,0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=PMT(0,0,\"\",0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=PMT(0,0,0,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=PMT(0,0,0,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
// PPMT
|
||||
"=PPMT()": "PPMT requires at least 4 arguments",
|
||||
"=PPMT(0,0,0,0,0,0,0)": "PPMT allows at most 6 arguments",
|
||||
"=PPMT(0,0,0,0,0,2)": "#N/A",
|
||||
"=PPMT(0,-1,0,0,0,0)": "#N/A",
|
||||
"=PPMT(0,1,0,0,0,0)": "#N/A",
|
||||
"=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",
|
||||
}
|
||||
for formula, expected := range mathCalcError {
|
||||
f := prepareCalcData(cellData)
|
||||
|
|
Loading…
Reference in New Issue