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