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  }