From f6167cb0c857809f06547822ff83270cf5c29d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bartoletti?= Date: Thu, 9 Jan 2025 09:07:59 +0100 Subject: [PATCH] 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 4aff12408ce8d22f64572371f96e04b4a6c73707) --- lib/pure/math.nim | 32 ++++++++++++++++++++++++++++++++ tests/stdlib/tmath.nim | 20 ++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index dc8257bfb6..7a5603ece3 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -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]) + diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index b28ec41a31..69534b16e2 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -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) +