diff --git a/base/Base.jl b/base/Base.jl index 1f0dfceb26492..3b95b44a33f0b 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -406,6 +406,9 @@ using .ScopedValues include("logging.jl") using .CoreLogging +# metaprogramming +include("meta.jl") + include("env.jl") # functions defined in Random @@ -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 diff --git a/base/combinatorics.jl b/base/combinatorics.jl index a169cfb9ecd77..3672a19e19998 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -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 diff --git a/test/combinatorics.jl b/test/combinatorics.jl index 862e3bfa37e1e..527bd86963a6f 100644 --- a/test/combinatorics.jl +++ b/test/combinatorics.jl @@ -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