Skip to content

Commit 53d35ef

Browse files
committed
ref qax-os#65, new formula function: EUROCONVERT
1 parent 40a9e52 commit 53d35ef

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

calc.go

+83
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ type formulaFuncs struct {
442442
// ERFC
443443
// ERFC.PRECISE
444444
// ERROR.TYPE
445+
// EUROCONVERT
445446
// EVEN
446447
// EXACT
447448
// EXP
@@ -16080,6 +16081,88 @@ func (fn *formulaFuncs) EFFECT(argsList *list.List) formulaArg {
1608016081
return newNumberFormulaArg(math.Pow(1+rate.Number/npery.Number, npery.Number) - 1)
1608116082
}
1608216083

16084+
// EUROCONVERT function convert a number to euro or from euro to a
16085+
// participating currency. You can also use it to convert a number from one
16086+
// participating currency to another by using the euro as an intermediary
16087+
// (triangulation). The syntax of the function is:
16088+
//
16089+
// EUROCONVERT(number,sourcecurrency,targetcurrency[,fullprecision,triangulationprecision])
16090+
//
16091+
func (fn *formulaFuncs) EUROCONVERT(argsList *list.List) formulaArg {
16092+
if argsList.Len() < 3 {
16093+
return newErrorFormulaArg(formulaErrorVALUE, "EUROCONVERT requires at least 3 arguments")
16094+
}
16095+
if argsList.Len() > 5 {
16096+
return newErrorFormulaArg(formulaErrorVALUE, "EUROCONVERT allows at most 5 arguments")
16097+
}
16098+
number := argsList.Front().Value.(formulaArg).ToNumber()
16099+
if number.Type != ArgNumber {
16100+
return number
16101+
}
16102+
sourceCurrency := argsList.Front().Next().Value.(formulaArg).Value()
16103+
targetCurrency := argsList.Front().Next().Next().Value.(formulaArg).Value()
16104+
fullPrec, triangulationPrec := newBoolFormulaArg(false), newNumberFormulaArg(0)
16105+
if argsList.Len() >= 4 {
16106+
if fullPrec = argsList.Front().Next().Next().Next().Value.(formulaArg).ToBool(); fullPrec.Type != ArgNumber {
16107+
return fullPrec
16108+
}
16109+
}
16110+
if argsList.Len() == 5 {
16111+
if triangulationPrec = argsList.Back().Value.(formulaArg).ToNumber(); triangulationPrec.Type != ArgNumber {
16112+
return triangulationPrec
16113+
}
16114+
}
16115+
convertTable := map[string][]float64{
16116+
"EUR": {1.0, 2},
16117+
"ATS": {13.7603, 2},
16118+
"BEF": {40.3399, 0},
16119+
"DEM": {1.95583, 2},
16120+
"ESP": {166.386, 0},
16121+
"FIM": {5.94573, 2},
16122+
"FRF": {6.55957, 2},
16123+
"IEP": {0.787564, 2},
16124+
"ITL": {1936.27, 0},
16125+
"LUF": {40.3399, 0},
16126+
"NLG": {2.20371, 2},
16127+
"PTE": {200.482, 2},
16128+
"GRD": {340.750, 2},
16129+
"SIT": {239.640, 2},
16130+
"MTL": {0.429300, 2},
16131+
"CYP": {0.585274, 2},
16132+
"SKK": {30.1260, 2},
16133+
"EEK": {15.6466, 2},
16134+
"LVL": {0.702804, 2},
16135+
"LTL": {3.45280, 2},
16136+
}
16137+
source, ok := convertTable[sourceCurrency]
16138+
if !ok {
16139+
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
16140+
}
16141+
target, ok := convertTable[targetCurrency]
16142+
if !ok {
16143+
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
16144+
}
16145+
if sourceCurrency == targetCurrency {
16146+
return number
16147+
}
16148+
var res float64
16149+
if sourceCurrency == "EUR" {
16150+
res = number.Number * target[0]
16151+
} else {
16152+
intermediate := number.Number / source[0]
16153+
if triangulationPrec.Number != 0 {
16154+
ratio := math.Pow(10, triangulationPrec.Number)
16155+
intermediate = math.Round(intermediate*ratio) / ratio
16156+
}
16157+
res = intermediate * target[0]
16158+
}
16159+
if fullPrec.Number != 1 {
16160+
ratio := math.Pow(10, target[1])
16161+
res = math.Round(res*ratio) / ratio
16162+
}
16163+
return newNumberFormulaArg(res)
16164+
}
16165+
1608316166
// FV function calculates the Future Value of an investment with periodic
1608416167
// constant payments and a constant interest rate. The syntax of the function
1608516168
// is:

calc_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,13 @@ func TestCalcCellValue(t *testing.T) {
19221922
// EFFECT
19231923
"=EFFECT(0.1,4)": "0.103812890625",
19241924
"=EFFECT(0.025,2)": "0.02515625",
1925+
// EUROCONVERT
1926+
"=EUROCONVERT(1.47,\"EUR\",\"EUR\")": "1.47",
1927+
"=EUROCONVERT(1.47,\"EUR\",\"DEM\")": "2.88",
1928+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\")": "0.44",
1929+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\",FALSE)": "0.44",
1930+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\",FALSE,3)": "0.44",
1931+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\",TRUE,3)": "0.43810592",
19251932
// FV
19261933
"=FV(0.05/12,60,-1000)": "68006.0828408434",
19271934
"=FV(0.1/4,16,-2000,0,1)": "39729.4608941662",
@@ -3958,6 +3965,14 @@ func TestCalcCellValue(t *testing.T) {
39583965
"=EFFECT(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
39593966
"=EFFECT(0,0)": "#NUM!",
39603967
"=EFFECT(1,0)": "#NUM!",
3968+
// EUROCONVERT
3969+
"=EUROCONVERT()": "EUROCONVERT requires at least 3 arguments",
3970+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\",TRUE,3,1)": "EUROCONVERT allows at most 5 arguments",
3971+
"=EUROCONVERT(\"\",\"FRF\",\"DEM\",TRUE,3)": "strconv.ParseFloat: parsing \"\": invalid syntax",
3972+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\",\"\",3)": "strconv.ParseBool: parsing \"\": invalid syntax",
3973+
"=EUROCONVERT(1.47,\"FRF\",\"DEM\",TRUE,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
3974+
"=EUROCONVERT(1.47,\"\",\"DEM\")": "#VALUE!",
3975+
"=EUROCONVERT(1.47,\"FRF\",\"\",TRUE,3)": "#VALUE!",
39613976
// FV
39623977
"=FV()": "FV requires at least 3 arguments",
39633978
"=FV(0,0,0,0,0,0,0)": "FV allows at most 5 arguments",

0 commit comments

Comments
 (0)