github.com/richardwilkes/toolbox@v1.121.0/eval/float_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  	"strings"
    14  
    15  	"github.com/richardwilkes/toolbox/xmath"
    16  	"golang.org/x/exp/constraints"
    17  )
    18  
    19  // FloatFunctions returns standard functions that work with constraints.Float.
    20  func FloatFunctions[T constraints.Float]() map[string]Function {
    21  	return map[string]Function{
    22  		"abs":   floatAbs[T],
    23  		"cbrt":  floatCubeRoot[T],
    24  		"ceil":  floatCeiling[T],
    25  		"exp":   floatBaseEExponential[T],
    26  		"exp2":  floatBase2Exponential[T],
    27  		"floor": floatFloor[T],
    28  		"if":    floatIf[T],
    29  		"log":   floatNaturalLog[T],
    30  		"log1p": floatNaturalLogSum1[T],
    31  		"log10": floatDecimalLog[T],
    32  		"max":   floatMaximum[T],
    33  		"min":   floatMinimum[T],
    34  		"round": floatRound[T],
    35  		"sqrt":  floatSquareRoot[T],
    36  	}
    37  }
    38  
    39  func floatAbs[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    40  	return floatSingleNumberFunc(e, arguments, xmath.Abs[T])
    41  }
    42  
    43  func floatBase2Exponential[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    44  	return floatSingleNumberFunc(e, arguments, xmath.Exp2[T])
    45  }
    46  
    47  func floatBaseEExponential[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    48  	return floatSingleNumberFunc(e, arguments, xmath.Exp[T])
    49  }
    50  
    51  func floatCeiling[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    52  	return floatSingleNumberFunc(e, arguments, xmath.Ceil[T])
    53  }
    54  
    55  func floatCubeRoot[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    56  	return floatSingleNumberFunc(e, arguments, xmath.Cbrt[T])
    57  }
    58  
    59  func floatDecimalLog[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    60  	return floatSingleNumberFunc(e, arguments, xmath.Log10[T])
    61  }
    62  
    63  func floatFloor[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    64  	return floatSingleNumberFunc(e, arguments, xmath.Floor[T])
    65  }
    66  
    67  func floatIf[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    68  	var arg string
    69  	arg, arguments = NextArg(arguments)
    70  	evaluated, err := e.EvaluateNew(arg)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	var value T
    75  	if value, err = floatFrom[T](evaluated); err != nil {
    76  		if s, ok := evaluated.(string); ok {
    77  			if s != "" && !strings.EqualFold(s, "false") {
    78  				value = 1
    79  			}
    80  		} else {
    81  			return nil, err
    82  		}
    83  	}
    84  	if value == 0 {
    85  		_, arguments = NextArg(arguments)
    86  	}
    87  	arg, _ = NextArg(arguments)
    88  	return e.EvaluateNew(arg)
    89  }
    90  
    91  func floatMaximum[T constraints.Float](e *Evaluator, arguments string) (any, error) {
    92  	maxValue := xmath.MinValue[T]()
    93  	for arguments != "" {
    94  		var arg string
    95  		arg, arguments = NextArg(arguments)
    96  		value, err := evalToFloat[T](e, arg)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  		maxValue = max(value, maxValue)
   101  	}
   102  	return maxValue, nil
   103  }
   104  
   105  func floatMinimum[T constraints.Float](e *Evaluator, arguments string) (any, error) {
   106  	minValue := xmath.MaxValue[T]()
   107  	for arguments != "" {
   108  		var arg string
   109  		arg, arguments = NextArg(arguments)
   110  		value, err := evalToFloat[T](e, arg)
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  		minValue = min(value, minValue)
   115  	}
   116  	return minValue, nil
   117  }
   118  
   119  func floatNaturalLog[T constraints.Float](e *Evaluator, arguments string) (any, error) {
   120  	return floatSingleNumberFunc(e, arguments, xmath.Log[T])
   121  }
   122  
   123  func floatNaturalLogSum1[T constraints.Float](e *Evaluator, arguments string) (any, error) {
   124  	value, err := evalToFloat[T](e, arguments)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return xmath.Log(value + 1), nil
   129  }
   130  
   131  func floatRound[T constraints.Float](e *Evaluator, arguments string) (any, error) {
   132  	return floatSingleNumberFunc(e, arguments, xmath.Round[T])
   133  }
   134  
   135  func floatSquareRoot[T constraints.Float](e *Evaluator, arguments string) (any, error) {
   136  	return floatSingleNumberFunc(e, arguments, xmath.Sqrt[T])
   137  }
   138  
   139  func evalToFloat[T constraints.Float](e *Evaluator, arg string) (T, error) {
   140  	evaluated, err := e.EvaluateNew(arg)
   141  	if err != nil {
   142  		return 0, err
   143  	}
   144  	return floatFrom[T](evaluated)
   145  }
   146  
   147  func floatSingleNumberFunc[T constraints.Float](e *Evaluator, arguments string, f func(T) T) (any, error) {
   148  	value, err := evalToFloat[T](e, arguments)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	return f(value), nil
   153  }