math: Add cumprod and cumproded (#23416)

This pull request adds the `cumproded` function along with its in-place
equivalent, `cumprod`, to the math library. These functions provide
functionality similar to `cumsum` and `cumsummed`, allowing users to
calculate the cumulative sum of elements.

The `cumprod` function computes the cumulative product of elements
in-place, while `cumproded` additionally returns the prod seq.

(cherry picked from commit 4aff12408c)
This commit is contained in:
Loïc Bartoletti
2025-01-09 09:07:59 +01:00
committed by narimiran
parent 72ce16990b
commit f6167cb0c8
2 changed files with 52 additions and 0 deletions

View File

@@ -1146,6 +1146,37 @@ func prod*[T](x: openArray[T]): T =
result = T(1)
for i in items(x): result = result * i
func cumprod*[T](x: var openArray[T]) =
## Transforms ``x`` in-place (must be declared as `var`) into its
## product.
##
## See also:
## * `prod proc <#sum,openArray[T]>`_
## * `cumproded proc <#cumproded,openArray[T]>`_ for a version which
## returns cumproded sequence
runnableExamples:
var a = [1, 2, 3, 4]
cumprod(a)
doAssert a == @[1, 2, 6, 24]
for i in 1 ..< x.len: x[i] = x[i-1] * x[i]
func cumproded*[T](x: openArray[T]): seq[T] =
## Return cumulative (aka prefix) product of ``x``.
##
## See also:
## * `prod proc <#prod,openArray[T]>`_
## * `cumprod proc <#cumprod,openArray[T]>`_ for the in-place version
runnableExamples:
let a = [1, 2, 3, 4]
doAssert cumproded(a) == @[1, 2, 6, 24]
result = @[]
let xLen = x.len
if xLen == 0:
return @[]
result.setLen(xLen)
result[0] = x[0]
for i in 1 ..< xLen: result[i] = result[i-1] * x[i]
func cumsummed*[T](x: openArray[T]): seq[T] =
## Returns the cumulative (aka prefix) summation of `x`.
##
@@ -1354,3 +1385,4 @@ func lcm*[T](x: openArray[T]): T {.since: (1, 1).} =
result = x[0]
for i in 1 ..< x.len:
result = lcm(result, x[i])

View File

@@ -245,6 +245,25 @@ template main() =
empty.cumsum
doAssert empty == @[]
block: # cumprod
block: #cumprod int seq return
let counts = [ 1, 2, 3, 4 ]
doAssert counts.cumproded == [ 1, 2, 6, 24 ]
block: # cumprod float seq return
let counts = [ 1.0, 2.0, 3.0, 4.0 ]
doAssert counts.cumproded == [ 1.0, 2.0, 6.0, 24.0 ]
block: # cumprod int in-place
var counts = [ 1, 2, 3, 4 ]
counts.cumprod
doAssert counts == [ 1, 2, 6, 24 ]
block: # cumprod float in-place
var counts = [ 1.0, 2.0, 3.0, 4.0 ]
counts.cumprod
doAssert counts == [ 1.0, 2.0, 6.0, 24.0 ]
block: # ^ compiles for valid types
doAssert: compiles(5 ^ 2)
doAssert: compiles(5.5 ^ 2)
@@ -525,3 +544,4 @@ when not defined(js) and not defined(danger):
doAssertRaises(OverflowDefect):
discard sum(x)