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  }