summaryrefslogtreecommitdiff
path: root/calc.go
diff options
context:
space:
mode:
Diffstat (limited to 'calc.go')
-rw-r--r--calc.go52
1 files changed, 52 insertions, 0 deletions
diff --git a/calc.go b/calc.go
index 5529056..66978bd 100644
--- a/calc.go
+++ b/calc.go
@@ -29,6 +29,8 @@ import (
"unsafe"
"github.com/xuri/efp"
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
)
// Excel formula errors
@@ -273,6 +275,7 @@ var tokenPriority = map[string]int{
// FINDB
// FISHER
// FISHERINV
+// FIXED
// FLOOR
// FLOOR.MATH
// FLOOR.PRECISE
@@ -4883,6 +4886,55 @@ func (fn *formulaFuncs) EXACT(argsList *list.List) formulaArg {
return newBoolFormulaArg(text1 == text2)
}
+// FIXED function rounds a supplied number to a specified number of decimal
+// places and then converts this into text. The syntax of the function is:
+//
+// FIXED(number,[decimals],[no_commas])
+//
+func (fn *formulaFuncs) FIXED(argsList *list.List) formulaArg {
+ if argsList.Len() < 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, "FIXED requires at least 1 argument")
+ }
+ if argsList.Len() > 3 {
+ return newErrorFormulaArg(formulaErrorVALUE, "FIXED allows at most 3 arguments")
+ }
+ numArg := argsList.Front().Value.(formulaArg).ToNumber()
+ if numArg.Type != ArgNumber {
+ return numArg
+ }
+ precision, decimals, noCommas := 0, 0, false
+ s := strings.Split(argsList.Front().Value.(formulaArg).Value(), ".")
+ if argsList.Len() == 1 && len(s) == 2 {
+ precision = len(s[1])
+ decimals = len(s[1])
+ }
+ if argsList.Len() >= 2 {
+ decimalsArg := argsList.Front().Next().Value.(formulaArg).ToNumber()
+ if decimalsArg.Type != ArgNumber {
+ return decimalsArg
+ }
+ decimals = int(decimalsArg.Number)
+ }
+ if argsList.Len() == 3 {
+ noCommasArg := argsList.Back().Value.(formulaArg).ToBool()
+ if noCommasArg.Type == ArgError {
+ return noCommasArg
+ }
+ noCommas = noCommasArg.Boolean
+ }
+ n := math.Pow(10, float64(decimals))
+ r := numArg.Number * n
+ fixed := float64(int(r+math.Copysign(0.5, r))) / n
+ if decimals > 0 {
+ precision = decimals
+ }
+ if noCommas {
+ return newStringFormulaArg(fmt.Sprintf(fmt.Sprintf("%%.%df", precision), fixed))
+ }
+ p := message.NewPrinter(language.English)
+ return newStringFormulaArg(p.Sprintf(fmt.Sprintf("%%.%df", precision), fixed))
+}
+
// FIND function returns the position of a specified character or sub-string
// within a supplied text string. The function is case-sensitive. The syntax
// of the function is: