diff --git a/docs/content/en/functions/math.md b/docs/content/en/functions/math.md index eb38fdd0b..29fe16985 100644 --- a/docs/content/en/functions/math.md +++ b/docs/content/en/functions/math.md @@ -4,7 +4,7 @@ description: Hugo provides nine mathematical operators in templates. godocref: date: 2017-02-01 publishdate: 2017-02-01 -lastmod: 2017-02-01 +lastmod: 2020-02-23 keywords: [math, operators] categories: [functions] menu: @@ -36,3 +36,6 @@ aliases: [] | `math.Ceil` | Returns the least integer value greater than or equal to the given number. | `{{math.Ceil 2.1}}` → `3` | | `math.Floor` | Returns the greatest integer value less than or equal to the given number. | `{{math.Floor 1.9}}` → `1` | | `math.Round` | Returns the nearest integer, rounding half away from zero. | `{{math.Round 1.5}}` → `2` | +| `math.Log` | Returns the natural logarithm of the given number. | `{{math.Log 42}}` → `3.737` | +| `math.Sqrt` | Returns the square root of the given number. | `{{math.Sqrt 81}}` → `9` | + diff --git a/tpl/math/init.go b/tpl/math/init.go index bbffb23aa..45240c5e1 100644 --- a/tpl/math/init.go +++ b/tpl/math/init.go @@ -64,6 +64,13 @@ func init() { }, ) + ns.AddMethodMapping(ctx.Sqrt, + nil, + [][2]string{ + {"{{math.Sqrt 81}}", "9"}, + }, + ) + ns.AddMethodMapping(ctx.Mod, []string{"mod"}, [][2]string{ diff --git a/tpl/math/math.go b/tpl/math/math.go index 08be42b47..950d95905 100644 --- a/tpl/math/math.go +++ b/tpl/math/math.go @@ -72,6 +72,18 @@ func (ns *Namespace) Log(a interface{}) (float64, error) { return math.Log(af), nil } +// Sqrt returns the square root of a number. +// NOTE: will return for NaN for negative values of a +func (ns *Namespace) Sqrt(a interface{}) (float64, error) { + af, err := cast.ToFloat64E(a) + + if err != nil { + return 0, errors.New("Sqrt operator can't be used with non integer or float value") + } + + return math.Sqrt(af), nil +} + // Mod returns a % b. func (ns *Namespace) Mod(a, b interface{}) (int64, error) { ai, erra := cast.ToInt64E(a) diff --git a/tpl/math/math_test.go b/tpl/math/math_test.go index 0beec8204..70f6749ba 100644 --- a/tpl/math/math_test.go +++ b/tpl/math/math_test.go @@ -153,6 +153,51 @@ func TestLog(t *testing.T) { c.Assert(err, qt.IsNil) c.Assert(result, qt.Equals, test.expect) } + + // Separate test for Log(-1) -- returns NaN + result, err := ns.Log(-1) + c.Assert(err, qt.IsNil) + c.Assert(result, qt.Satisfies, math.IsNaN) +} + +func TestSqrt(t *testing.T) { + t.Parallel() + c := qt.New(t) + + ns := New() + + for _, test := range []struct { + a interface{} + expect interface{} + }{ + {81, float64(9)}, + {0.25, float64(0.5)}, + {0, float64(0)}, + {"abc", false}, + } { + + result, err := ns.Sqrt(test.a) + + if b, ok := test.expect.(bool); ok && !b { + c.Assert(err, qt.Not(qt.IsNil)) + continue + } + + // we compare only 4 digits behind point if its a real float + // otherwise we usually get different float values on the last positions + if result != math.Inf(-1) { + result = float64(int(result*10000)) / 10000 + } + + c.Assert(err, qt.IsNil) + c.Assert(result, qt.Equals, test.expect) + } + + // Separate test for Sqrt(-1) -- returns NaN + result, err := ns.Sqrt(-1) + c.Assert(err, qt.IsNil) + c.Assert(result, qt.Satisfies, math.IsNaN) + } func TestMod(t *testing.T) {