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  }