math.go (4923B)
1 // Copyright 2017 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 // Package math provides template functions for mathematical operations. 15 package math 16 17 import ( 18 "errors" 19 "math" 20 "sync/atomic" 21 22 _math "github.com/gohugoio/hugo/common/math" 23 24 "github.com/spf13/cast" 25 ) 26 27 // New returns a new instance of the math-namespaced template functions. 28 func New() *Namespace { 29 return &Namespace{} 30 } 31 32 // Namespace provides template functions for the "math" namespace. 33 type Namespace struct{} 34 35 // Add adds the two addends n1 and n2. 36 func (ns *Namespace) Add(n1, n2 any) (any, error) { 37 return _math.DoArithmetic(n1, n2, '+') 38 } 39 40 // Ceil returns the least integer value greater than or equal to n. 41 func (ns *Namespace) Ceil(n any) (float64, error) { 42 xf, err := cast.ToFloat64E(n) 43 if err != nil { 44 return 0, errors.New("Ceil operator can't be used with non-float value") 45 } 46 47 return math.Ceil(xf), nil 48 } 49 50 // Div divides n1 by n2. 51 func (ns *Namespace) Div(n1, n2 any) (any, error) { 52 return _math.DoArithmetic(n1, n2, '/') 53 } 54 55 // Floor returns the greatest integer value less than or equal to n. 56 func (ns *Namespace) Floor(n any) (float64, error) { 57 xf, err := cast.ToFloat64E(n) 58 if err != nil { 59 return 0, errors.New("Floor operator can't be used with non-float value") 60 } 61 62 return math.Floor(xf), nil 63 } 64 65 // Log returns the natural logarithm of the number n. 66 func (ns *Namespace) Log(n any) (float64, error) { 67 af, err := cast.ToFloat64E(n) 68 if err != nil { 69 return 0, errors.New("Log operator can't be used with non integer or float value") 70 } 71 72 return math.Log(af), nil 73 } 74 75 // Max returns the greater of the two numbers n1 or n2. 76 func (ns *Namespace) Max(n1, n2 any) (float64, error) { 77 af, erra := cast.ToFloat64E(n1) 78 bf, errb := cast.ToFloat64E(n2) 79 80 if erra != nil || errb != nil { 81 return 0, errors.New("Max operator can't be used with non-float value") 82 } 83 84 return math.Max(af, bf), nil 85 } 86 87 // Min returns the smaller of two numbers n1 or n2. 88 func (ns *Namespace) Min(n1, n2 any) (float64, error) { 89 af, erra := cast.ToFloat64E(n1) 90 bf, errb := cast.ToFloat64E(n2) 91 92 if erra != nil || errb != nil { 93 return 0, errors.New("Min operator can't be used with non-float value") 94 } 95 96 return math.Min(af, bf), nil 97 } 98 99 // Mod returns n1 % n2. 100 func (ns *Namespace) Mod(n1, n2 any) (int64, error) { 101 ai, erra := cast.ToInt64E(n1) 102 bi, errb := cast.ToInt64E(n2) 103 104 if erra != nil || errb != nil { 105 return 0, errors.New("modulo operator can't be used with non integer value") 106 } 107 108 if bi == 0 { 109 return 0, errors.New("the number can't be divided by zero at modulo operation") 110 } 111 112 return ai % bi, nil 113 } 114 115 // ModBool returns the boolean of n1 % n2. If n1 % n2 == 0, return true. 116 func (ns *Namespace) ModBool(n1, n2 any) (bool, error) { 117 res, err := ns.Mod(n1, n2) 118 if err != nil { 119 return false, err 120 } 121 122 return res == int64(0), nil 123 } 124 125 // Mul multiplies the two numbers n1 and n2. 126 func (ns *Namespace) Mul(n1, n2 any) (any, error) { 127 return _math.DoArithmetic(n1, n2, '*') 128 } 129 130 // Pow returns n1 raised to the power of n2. 131 func (ns *Namespace) Pow(n1, n2 any) (float64, error) { 132 af, erra := cast.ToFloat64E(n1) 133 bf, errb := cast.ToFloat64E(n2) 134 135 if erra != nil || errb != nil { 136 return 0, errors.New("Pow operator can't be used with non-float value") 137 } 138 139 return math.Pow(af, bf), nil 140 } 141 142 // Round returns the integer nearest to n, rounding half away from zero. 143 func (ns *Namespace) Round(n any) (float64, error) { 144 xf, err := cast.ToFloat64E(n) 145 if err != nil { 146 return 0, errors.New("Round operator can't be used with non-float value") 147 } 148 149 return _round(xf), nil 150 } 151 152 // Sqrt returns the square root of the number n. 153 func (ns *Namespace) Sqrt(n any) (float64, error) { 154 af, err := cast.ToFloat64E(n) 155 if err != nil { 156 return 0, errors.New("Sqrt operator can't be used with non integer or float value") 157 } 158 159 return math.Sqrt(af), nil 160 } 161 162 // Sub subtracts n2 from n1. 163 func (ns *Namespace) Sub(n1, n2 any) (any, error) { 164 return _math.DoArithmetic(n1, n2, '-') 165 } 166 167 var counter uint64 168 169 // Counter increments and returns a global counter. 170 // This was originally added to be used in tests where now.UnixNano did not 171 // have the needed precision (especially on Windows). 172 // Note that given the parallel nature of Hugo, you cannot use this to get sequences of numbers, 173 // and the counter will reset on new builds. 174 func (ns *Namespace) Counter() uint64 { 175 return atomic.AddUint64(&counter, uint64(1)) 176 }