Skip to content

Commit

Permalink
math: Add cumprod and cumproded (#23416)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lbartoletti authored Jan 9, 2025
1 parent 8ed0a63 commit 4aff124
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
32 changes: 32 additions & 0 deletions lib/pure/math.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,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`.
##
Expand Down Expand Up @@ -1353,3 +1384,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])

20 changes: 20 additions & 0 deletions tests/stdlib/tmath.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -525,3 +544,4 @@ when not defined(js) and not defined(danger):

doAssertRaises(OverflowDefect):
discard sum(x)

0 comments on commit 4aff124

Please sign in to comment.