github.com/richardwilkes/toolbox@v1.121.0/eval/fixed_operators.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 "fmt" 14 "math" 15 16 "github.com/richardwilkes/toolbox/errs" 17 "github.com/richardwilkes/toolbox/xmath/fixed" 18 "github.com/richardwilkes/toolbox/xmath/fixed/f64" 19 ) 20 21 // FixedOperators returns standard operators that work with 64-bit fixed-point values. 22 func FixedOperators[T fixed.Dx](divideByZeroReturnsZero bool) []*Operator { 23 var divide, modulo OpFunc 24 if divideByZeroReturnsZero { 25 divide = fixedDivideAllowDivideByZero[T] 26 modulo = fixedModuloAllowDivideByZero[T] 27 } else { 28 divide = fixedDivide[T] 29 modulo = fixedModulo[T] 30 } 31 return []*Operator{ 32 OpenParen(), 33 CloseParen(), 34 LogicalOr(fixedLogicalOr[T]), 35 LogicalAnd(fixedLogicalAnd[T]), 36 Not(fixedNot[T]), 37 Equal(fixedEqual[T]), 38 NotEqual(fixedNotEqual[T]), 39 GreaterThan(fixedGreaterThan[T]), 40 GreaterThanOrEqual(fixedGreaterThanOrEqual[T]), 41 LessThan(fixedLessThan[T]), 42 LessThanOrEqual(fixedLessThanOrEqual[T]), 43 Add(fixedAdd[T], fixedAddUnary[T]), 44 Subtract(fixedSubtract[T], fixedSubtractUnary[T]), 45 Multiply(fixedMultiply[T]), 46 Divide(divide), 47 Modulo(modulo), 48 Power(fixedPower[T]), 49 } 50 } 51 52 func fixedNot[T fixed.Dx](arg any) (any, error) { 53 if b, ok := arg.(bool); ok { 54 return !b, nil 55 } 56 v, err := FixedFrom[T](arg) 57 if err != nil { 58 return nil, err 59 } 60 if v == 0 { 61 return true, nil 62 } 63 return false, nil 64 } 65 66 func fixedLogicalOr[T fixed.Dx](left, right any) (any, error) { 67 l, err := FixedFrom[T](left) 68 if err != nil { 69 return nil, err 70 } 71 if l != 0 { 72 return true, nil 73 } 74 var r f64.Int[T] 75 r, err = FixedFrom[T](right) 76 if err != nil { 77 return nil, err 78 } 79 return r != 0, nil 80 } 81 82 func fixedLogicalAnd[T fixed.Dx](left, right any) (any, error) { 83 l, err := FixedFrom[T](left) 84 if err != nil { 85 return nil, err 86 } 87 if l == 0 { 88 return false, nil 89 } 90 var r f64.Int[T] 91 r, err = FixedFrom[T](right) 92 if err != nil { 93 return nil, err 94 } 95 return r != 0, nil 96 } 97 98 func fixedEqual[T fixed.Dx](left, right any) (any, error) { 99 var r f64.Int[T] 100 l, err := FixedFrom[T](left) 101 if err == nil { 102 r, err = FixedFrom[T](right) 103 } 104 if err != nil { 105 return fmt.Sprintf("%v", left) == fmt.Sprintf("%v", right), nil 106 } 107 return l == r, nil 108 } 109 110 func fixedNotEqual[T fixed.Dx](left, right any) (any, error) { 111 var r f64.Int[T] 112 l, err := FixedFrom[T](left) 113 if err == nil { 114 r, err = FixedFrom[T](right) 115 } 116 if err != nil { 117 return fmt.Sprintf("%v", left) != fmt.Sprintf("%v", right), nil 118 } 119 return l != r, nil 120 } 121 122 func fixedGreaterThan[T fixed.Dx](left, right any) (any, error) { 123 var r f64.Int[T] 124 l, err := FixedFrom[T](left) 125 if err == nil { 126 r, err = FixedFrom[T](right) 127 } 128 if err != nil { 129 return fmt.Sprintf("%v", left) > fmt.Sprintf("%v", right), nil 130 } 131 return l > r, nil 132 } 133 134 func fixedGreaterThanOrEqual[T fixed.Dx](left, right any) (any, error) { 135 var r f64.Int[T] 136 l, err := FixedFrom[T](left) 137 if err == nil { 138 r, err = FixedFrom[T](right) 139 } 140 if err != nil { 141 return fmt.Sprintf("%v", left) >= fmt.Sprintf("%v", right), nil 142 } 143 return l >= r, nil 144 } 145 146 func fixedLessThan[T fixed.Dx](left, right any) (any, error) { 147 var r f64.Int[T] 148 l, err := FixedFrom[T](left) 149 if err == nil { 150 r, err = FixedFrom[T](right) 151 } 152 if err != nil { 153 return fmt.Sprintf("%v", left) < fmt.Sprintf("%v", right), nil 154 } 155 return l < r, nil 156 } 157 158 func fixedLessThanOrEqual[T fixed.Dx](left, right any) (any, error) { 159 var r f64.Int[T] 160 l, err := FixedFrom[T](left) 161 if err == nil { 162 r, err = FixedFrom[T](right) 163 } 164 if err != nil { 165 return fmt.Sprintf("%v", left) <= fmt.Sprintf("%v", right), nil 166 } 167 return l <= r, nil 168 } 169 170 func fixedAdd[T fixed.Dx](left, right any) (any, error) { 171 var r f64.Int[T] 172 l, err := FixedFrom[T](left) 173 if err == nil { 174 r, err = FixedFrom[T](right) 175 } 176 if err != nil { 177 return fmt.Sprintf("%v%v", left, right), nil 178 } 179 return l + r, nil 180 } 181 182 func fixedAddUnary[T fixed.Dx](arg any) (any, error) { 183 return FixedFrom[T](arg) 184 } 185 186 func fixedSubtract[T fixed.Dx](left, right any) (any, error) { 187 l, err := FixedFrom[T](left) 188 if err != nil { 189 return nil, err 190 } 191 var r f64.Int[T] 192 r, err = FixedFrom[T](right) 193 if err != nil { 194 return nil, err 195 } 196 return l - r, nil 197 } 198 199 func fixedSubtractUnary[T fixed.Dx](arg any) (any, error) { 200 v, err := FixedFrom[T](arg) 201 if err != nil { 202 return nil, err 203 } 204 return -v, nil 205 } 206 207 func fixedMultiply[T fixed.Dx](left, right any) (any, error) { 208 l, err := FixedFrom[T](left) 209 if err != nil { 210 return nil, err 211 } 212 var r f64.Int[T] 213 r, err = FixedFrom[T](right) 214 if err != nil { 215 return nil, err 216 } 217 return l.Mul(r), nil 218 } 219 220 func fixedDivide[T fixed.Dx](left, right any) (any, error) { 221 l, err := FixedFrom[T](left) 222 if err != nil { 223 return nil, err 224 } 225 var r f64.Int[T] 226 r, err = FixedFrom[T](right) 227 if err != nil { 228 return nil, err 229 } 230 if r == 0 { 231 return nil, errs.New("divide by zero") 232 } 233 return l.Div(r), nil 234 } 235 236 func fixedDivideAllowDivideByZero[T fixed.Dx](left, right any) (any, error) { 237 l, err := FixedFrom[T](left) 238 if err != nil { 239 return nil, err 240 } 241 var r f64.Int[T] 242 r, err = FixedFrom[T](right) 243 if err != nil { 244 return nil, err 245 } 246 if r == 0 { 247 return r, nil 248 } 249 return l.Div(r), nil 250 } 251 252 func fixedModulo[T fixed.Dx](left, right any) (any, error) { 253 l, err := FixedFrom[T](left) 254 if err != nil { 255 return nil, err 256 } 257 var r f64.Int[T] 258 r, err = FixedFrom[T](right) 259 if err != nil { 260 return nil, err 261 } 262 if r == 0 { 263 return nil, errs.New("divide by zero") 264 } 265 return l.Mod(r), nil 266 } 267 268 func fixedModuloAllowDivideByZero[T fixed.Dx](left, right any) (any, error) { 269 l, err := FixedFrom[T](left) 270 if err != nil { 271 return nil, err 272 } 273 var r f64.Int[T] 274 r, err = FixedFrom[T](right) 275 if err != nil { 276 return nil, err 277 } 278 if r == 0 { 279 return r, nil 280 } 281 return l.Mod(r), nil 282 } 283 284 func fixedPower[T fixed.Dx](left, right any) (any, error) { 285 l, err := FixedFrom[T](left) 286 if err != nil { 287 return nil, err 288 } 289 var r f64.Int[T] 290 r, err = FixedFrom[T](right) 291 if err != nil { 292 return nil, err 293 } 294 return f64.From[T](math.Pow(f64.As[T, float64](l), f64.As[T, float64](r))), nil 295 } 296 297 // FixedFrom attempts to convert the arg into one of the fixed.F64 types. 298 func FixedFrom[T fixed.Dx](arg any) (f64.Int[T], error) { 299 switch a := arg.(type) { 300 case bool: 301 if a { 302 return f64.From[T, int](1), nil 303 } 304 return 0, nil 305 case f64.Int[T]: 306 return a, nil 307 case string: 308 return f64.FromString[T](a) 309 default: 310 return 0, errs.Newf("not a number: %v", arg) 311 } 312 }