Repository: gohugoio/hugo (language: go)

Issue:
Add math.Rand that calls rand.Float64
Currently random ints have to be created like so:
```
{{ index (shuffle (seq 0 9)) 0 }}
```
Where 0 and 9 specify the range for the number to be generate in.

And random floats have to be generated like so:
```
{{ mul 0.1 (index (shuffle (seq 0 90)) 0) }}
```
Where 0.1 is the amount of precision desired, `0*the precision` is the minimum bound, and `90*the precision` is the upper bound.

It would be much easier if their were functions:
```
{{ randInt 0 9 }}
{{ randFloat 0.1 0 9 }} // Note that this will generate a number between 0 and 9 without having to change the bounds to adjust for the precision desired
```


Discussion / hints:
Out of curiosity, how do you currently use the random numbers generated with your examples above?

I suspect we'd be more likely to implement a single `math.Rand` function using:
<https://pkg.go.dev/math/rand#Float64>

```text
{{ math.Rand | mul 10 | add 1 | int }} --> random int between 1 and 10 inclusive
```
I'm shifting images that are placed on top of each other slightly so that all of them are visible. This requires generating a random float that is between 2 numbers.

Fix patch:
diff --git a/docs/content/en/functions/math/Rand.md b/docs/content/en/functions/math/Rand.md
new file mode 100644
index 00000000000..4cdf02fd349
--- /dev/null
+++ b/docs/content/en/functions/math/Rand.md
@@ -0,0 +1,44 @@
+---
+title: math.Rand
+description: Returns a pseudo-random number in the half-open interval [0.0, 1.0).
+categories: []
+keywords: []
+action:
+  aliases: []
+  related: []
+  returnType: float64
+  signatures: [math.Rand]
+---
+
+The `math.Rand` function returns a pseudo-random number in the [half-open interval] [0.0, 1.0).
+
+```go-html-template
+{{ math.Rand }} → 0.6312770459590062
+```
+
+To generate a random integer in the [closed interval] [0, 5]:
+
+```go-html-template
+{{ math.Rand | mul 6 | math.Floor }}
+```
+
+To generate a random integer in the closed interval [1, 6]:
+
+```go-html-template
+{{ math.Rand | mul 6 | math.Ceil }}
+```
+
+To generate a random float, with one digit after the decimal point, in the closed interval [0, 4.9]:
+
+```go-html-template
+{{ div (math.Rand | mul 50 | math.Floor) 10 }}
+```
+
+To generate a random float, with one digit after the decimal point, in the closed interval [0.1, 5.0]:
+
+```go-html-template
+{{ div (math.Rand | mul 50 | math.Ceil) 10 }}
+```
+
+[closed interval]: /getting-started/glossary/#interval
+[half-open interval]: /getting-started/glossary/#interval
diff --git a/docs/content/en/getting-started/glossary.md b/docs/content/en/getting-started/glossary.md
index edf64ab8946..dce3d152796 100644
--- a/docs/content/en/getting-started/glossary.md
+++ b/docs/content/en/getting-started/glossary.md
@@ -147,6 +147,16 @@ A numeric data type without a fractional component. For example, `42`.
 
 Software design and development efforts that enable [localization](#localization). See the [W3C definition](https://www.w3.org/International/questions/qa-i18n). Abbreviated i18n.
 
+###### interval
+
+An [interval](https://en.wikipedia.org/wiki/Interval_(mathematics)) is a range of numbers between two endpoints: closed, open, or half-open.
+
+- A _closed_ interval, denoted by brackets, includes its endpoints. For example, [0,&nbsp;1]&nbsp;is the interval where `0 <= x <= 1`.
+
+- An _open_ interval, denoted by parenthesis, excludes its endpoints. For example, (0,&nbsp;1)&nbsp;is the interval where `0 < x < 1`.
+
+- A _half-open_ interval includes only one of its endpoints. For example, (0,&nbsp;1]&nbsp;is the _left-open_ interval where `0 < x <= 1`, while [0,&nbsp;1)&nbsp;is the _right-open_ interval where `0 <= x < 1`.
+
 ###### kind
 
 See [page kind](#page-kind).
diff --git a/tpl/math/init.go b/tpl/math/init.go
index 8596ff64705..fa136767176 100644
--- a/tpl/math/init.go
+++ b/tpl/math/init.go
@@ -115,6 +115,13 @@ func init() {
 			},
 		)
 
+		ns.AddMethodMapping(ctx.Rand,
+			nil,
+			[][2]string{
+				{"{{ math.Rand }}", "0.6312770459590062"},
+			},
+		)
+
 		ns.AddMethodMapping(ctx.Round,
 			nil,
 			[][2]string{
diff --git a/tpl/math/math.go b/tpl/math/math.go
index a921bd7ada3..0f8db11e2a8 100644
--- a/tpl/math/math.go
+++ b/tpl/math/math.go
@@ -18,6 +18,7 @@ import (
 	"errors"
 	"fmt"
 	"math"
+	"math/rand"
 	"reflect"
 	"sync/atomic"
 
@@ -157,6 +158,11 @@ func (ns *Namespace) Pow(n1, n2 any) (float64, error) {
 	return math.Pow(af, bf), nil
 }
 
+// Rand returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0).
+func (ns *Namespace) Rand() float64 {
+	return rand.Float64()
+}
+
 // Round returns the integer nearest to n, rounding half away from zero.
 func (ns *Namespace) Round(n any) (float64, error) {
 	xf, err := cast.ToFloat64E(n)


Test patch:
diff --git a/tpl/tplimpl/template_funcs_test.go b/tpl/tplimpl/template_funcs_test.go
index 9cc84934b9f..f1ab3d65959 100644
--- a/tpl/tplimpl/template_funcs_test.go
+++ b/tpl/tplimpl/template_funcs_test.go
@@ -61,12 +61,10 @@ title: "**BatMan**"
 		ns := nsf(d)
 		for _, mm := range ns.MethodMappings {
 			for _, example := range mm.Examples {
-				if strings.Contains(example[0], "errorf") {
-					// This will fail the build, so skip for now.
-					continue
-				}
-				if strings.Contains(example[0], "transform.XMLEscape") {
-					// This will fail the build, so skip for now.
+				// These will fail the build, so skip.
+				if strings.Contains(example[0], "errorf") ||
+					strings.Contains(example[0], "transform.XMLEscape") ||
+					strings.Contains(example[0], "math.Rand") {
 					continue
 				}
 				templates = append(templates, example[0])