Skip to content

Commit

Permalink
improve effects of factorial (JuliaLang#54320)
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk authored and lazarusA committed Jul 12, 2024
1 parent 29ab3e5 commit 8f1496e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 27 deletions.
6 changes: 3 additions & 3 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ using .ScopedValues
include("logging.jl")
using .CoreLogging

# metaprogramming
include("meta.jl")

include("env.jl")

# functions defined in Random
Expand Down Expand Up @@ -495,9 +498,6 @@ include("irrationals.jl")
include("mathconstants.jl")
using .MathConstants: ℯ, π, pi

# metaprogramming
include("meta.jl")

# Stack frames and traces
include("stacktraces.jl")
using .StackTraces
Expand Down
33 changes: 20 additions & 13 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,30 @@

# Factorials

const _fact_table64 = Vector{Int64}(undef, 20)
_fact_table64[1] = 1
for n in 2:20
_fact_table64[n] = _fact_table64[n-1] * n
const _fact_table64 = let _fact_table64 = Vector{Int64}(undef, 20)
_fact_table64[1] = 1
for n in 2:20
_fact_table64[n] = _fact_table64[n-1] * n
end
Tuple(_fact_table64)
end

const _fact_table128 = Vector{UInt128}(undef, 34)
_fact_table128[1] = 1
for n in 2:34
_fact_table128[n] = _fact_table128[n-1] * n
const _fact_table128 = let _fact_table128 = Vector{UInt128}(undef, 34)
_fact_table128[1] = 1
for n in 2:34
_fact_table128[n] = _fact_table128[n-1] * n
end
Tuple(_fact_table128)
end

function factorial_lookup(n::Integer, table, lim)
n < 0 && throw(DomainError(n, "`n` must not be negative."))
n > lim && throw(OverflowError(string(n, " is too large to look up in the table; consider using `factorial(big(", n, "))` instead")))
n == 0 && return one(n)
@inbounds f = table[n]
function factorial_lookup(
n::Union{Checked.SignedInt,Checked.UnsignedInt},
table::Union{NTuple{20,Int64},NTuple{34,UInt128}}, lim::Int)
idx = Int(n)
idx < 0 && throw(DomainError(n, "`n` must not be negative."))
idx > lim && throw(OverflowError(lazy"$n is too large to look up in the table; consider using `factorial(big($n))` instead"))
idx == 0 && return one(n)
f = getfield(table, idx)
return oftype(n, f)
end

Expand Down
17 changes: 6 additions & 11 deletions test/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,12 @@ end
end

@testset "factorial" begin
@test factorial(7) == 5040
@test factorial(Int8(7)) == 5040
@test factorial(UInt8(7)) == 5040
@test factorial(Int16(7)) == 5040
@test factorial(UInt16(7)) == 5040
@test factorial(Int32(7)) == 5040
@test factorial(UInt32(7)) == 5040
@test factorial(Int64(7)) == 5040
@test factorial(UInt64(7)) == 5040
@test factorial(Int128(7)) == 5040
@test factorial(UInt128(7)) == 5040
for T = Base.uniontypes(Union{Base.Checked.SignedInt,Base.Checked.UnsignedInt})
@testset let T = T
@test factorial(T(7)) == 5040
@test Core.Compiler.is_foldable(Base.infer_effects(factorial, (T,)))
end
end
@test factorial(0) == 1
@test_throws DomainError factorial(-1)
@test factorial(Int64(20)) == 2432902008176640000
Expand Down

0 comments on commit 8f1496e

Please sign in to comment.