From 6a8e2d2e55c4ae8ad120ae8dcd7c09f3a37d7796 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 3 Oct 2023 09:52:47 +0200 Subject: [PATCH] Ensure rising_factorial(::Int,::Int) detects overflows (#1453) --- src/generic/Misc/Rings.jl | 10 +++++++++- test/misc-test.jl | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/generic/Misc/Rings.jl b/src/generic/Misc/Rings.jl index 4a66e21497..35a79fdd63 100644 --- a/src/generic/Misc/Rings.jl +++ b/src/generic/Misc/Rings.jl @@ -52,6 +52,10 @@ julia> rising_factorial(4, 2) function rising_factorial(x::RingElement, n::Integer) n < 0 && throw(DomainError(n, "Argument must be non-negative")) n == 0 && return one(x) + n == 1 && return x + if x isa Integer + return reduce(Base.checked_mul, x+i-1 for i in 1:Int(n)) + end return prod(x+i-1 for i in 1:Int(n)) end @@ -73,14 +77,18 @@ julia> rising_factorial2(x, 1) julia> rising_factorial2(x, 2) (x^2 + x, 2*x + 1) -julia> rising_factorial2(4,2) +julia> rising_factorial2(4, 2) (20, 9) ``` """ function rising_factorial2(x::RingElement, n::Integer) n < 0 && throw(DomainError(n, "Argument must be non-negative")) n == 0 && return (one(x), zero(x)) + n == 1 && return (x, one(x)) f, F = rising_factorial2(x, Int(n)-1) # use product rule: [(x+n-1)*f(x)]' = (x+n-1)'*f(x) + (x+n-1)*f'(x) + if x isa Integer + return Base.checked_mul(x+n-1, f), f + Base.checked_mul(x+n-1, F) + end return (x+n-1)*f, f + (x+n-1)*F end diff --git a/test/misc-test.jl b/test/misc-test.jl index 1911f12acd..e5dc6d1660 100644 --- a/test/misc-test.jl +++ b/test/misc-test.jl @@ -13,3 +13,9 @@ @test_throws ErrorException evaluate(:(x + x^2 + f(x)), Dict(:x => 1)) @test_throws ErrorException evaluate((Expr(:x)), Dict(:y => 1)) end + +@testset "rising_factorial" begin + + @test_throws OverflowError rising_factorial(10,30) + @test_throws OverflowError rising_factorial2(10,30) +end