github.com/richardwilkes/toolbox@v1.121.0/eval/fixed_function.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package eval 11 12 import ( 13 "math" 14 "strings" 15 16 "github.com/richardwilkes/toolbox/xmath/fixed" 17 "github.com/richardwilkes/toolbox/xmath/fixed/f64" 18 ) 19 20 // FixedFunctions returns standard functions that work with 64-bit fixed-point values. 21 func FixedFunctions[T fixed.Dx]() map[string]Function { 22 return map[string]Function{ 23 "abs": fixedAbsolute[T], 24 "cbrt": fixedCubeRoot[T], 25 "ceil": fixedCeiling[T], 26 "exp": fixedBaseEExponential[T], 27 "exp2": fixedBase2Exponential[T], 28 "floor": fixedFloor[T], 29 "if": fixedIf[T], 30 "log": fixedNaturalLog[T], 31 "log1p": fixedNaturalLogSum1[T], 32 "log10": fixedDecimalLog[T], 33 "max": fixedMaximum[T], 34 "min": fixedMinimum[T], 35 "round": fixedRound[T], 36 "sqrt": fixedSquareRoot[T], 37 } 38 } 39 40 func fixedAbsolute[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 41 value, err := evalToFixed[T](e, arguments) 42 if err != nil { 43 return nil, err 44 } 45 return any(&value).(interface{ Abs() f64.Int[T] }).Abs(), nil 46 } 47 48 func fixedBase2Exponential[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 49 return fixedSingleNumberFunc[T](e, arguments, math.Exp2) 50 } 51 52 func fixedBaseEExponential[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 53 return fixedSingleNumberFunc[T](e, arguments, math.Exp) 54 } 55 56 func fixedCeiling[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 57 value, err := evalToFixed[T](e, arguments) 58 if err != nil { 59 return nil, err 60 } 61 return any(&value).(interface{ Ceil() f64.Int[T] }).Ceil(), nil 62 } 63 64 func fixedCubeRoot[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 65 return fixedSingleNumberFunc[T](e, arguments, math.Cbrt) 66 } 67 68 func fixedDecimalLog[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 69 return fixedSingleNumberFunc[T](e, arguments, math.Log10) 70 } 71 72 func fixedFloor[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 73 value, err := evalToFixed[T](e, arguments) 74 if err != nil { 75 return nil, err 76 } 77 return any(&value).(interface{ Trunc() f64.Int[T] }).Trunc(), nil 78 } 79 80 func fixedIf[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 81 var arg string 82 arg, arguments = NextArg(arguments) 83 evaluated, err := e.EvaluateNew(arg) 84 if err != nil { 85 return nil, err 86 } 87 var value f64.Int[T] 88 if value, err = FixedFrom[T](evaluated); err != nil { 89 if s, ok := evaluated.(string); ok { 90 if s != "" && !strings.EqualFold(s, "false") { 91 value = any(&value).(interface{ Inc() f64.Int[T] }).Inc() 92 } 93 } else { 94 return nil, err 95 } 96 } 97 if value == 0 { 98 _, arguments = NextArg(arguments) 99 } 100 arg, _ = NextArg(arguments) 101 return e.EvaluateNew(arg) 102 } 103 104 func fixedMaximum[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 105 maximum := f64.Int[T](f64.Min) 106 for arguments != "" { 107 var arg string 108 arg, arguments = NextArg(arguments) 109 value, err := evalToFixed[T](e, arg) 110 if err != nil { 111 return nil, err 112 } 113 maximum = maximum.Max(value) 114 } 115 return maximum, nil 116 } 117 118 func fixedMinimum[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 119 minimum := f64.Int[T](f64.Max) 120 for arguments != "" { 121 var arg string 122 arg, arguments = NextArg(arguments) 123 value, err := evalToFixed[T](e, arg) 124 if err != nil { 125 return nil, err 126 } 127 minimum = minimum.Min(value) 128 } 129 return minimum, nil 130 } 131 132 func fixedNaturalLog[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 133 return fixedSingleNumberFunc[T](e, arguments, math.Log) 134 } 135 136 func fixedNaturalLogSum1[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 137 value, err := evalToFixed[T](e, arguments) 138 if err != nil { 139 return nil, err 140 } 141 value = any(&value).(interface{ Inc() f64.Int[T] }).Inc() 142 return f64.From[T](math.Log(any(&value).(interface{ AsFloat64() float64 }).AsFloat64())), nil 143 } 144 145 func fixedRound[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 146 value, err := evalToFixed[T](e, arguments) 147 if err != nil { 148 return nil, err 149 } 150 return any(&value).(interface{ Round() f64.Int[T] }).Round(), nil 151 } 152 153 func fixedSquareRoot[T fixed.Dx](e *Evaluator, arguments string) (any, error) { 154 return fixedSingleNumberFunc[T](e, arguments, math.Sqrt) 155 } 156 157 func evalToFixed[T fixed.Dx](e *Evaluator, arg string) (f64.Int[T], error) { 158 evaluated, err := e.EvaluateNew(arg) 159 if err != nil { 160 return 0, err 161 } 162 return FixedFrom[T](evaluated) 163 } 164 165 func fixedSingleNumberFunc[T fixed.Dx](e *Evaluator, arguments string, f func(float64) float64) (any, error) { 166 value, err := evalToFixed[T](e, arguments) 167 if err != nil { 168 return nil, err 169 } 170 return f64.From[T](f(f64.As[T, float64](value))), nil 171 }