Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
@inbounds 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
Comment on lines +80 to +85
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
types = Base.uniontypes(Union{Base.Checked.SignedInt,Base.Checked.UnsignedInt})
@testset for T = types
@test factorial(T(7)) == 5040
@test Core.Compiler.is_foldable(Base.infer_effects(factorial, (T,)))
end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer the contextual testset.

Copy link
Contributor

@Seelengrab Seelengrab May 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @testset for will also show the iterated object as context on a failure, but aggregated and not as individual testsets:

julia> using Test

julia> types = Base.uniontypes(Union{Base.Checked.SignedInt,Base.Checked.UnsignedInt});

julia> @testset begin
       @testset for T = types
           @test factorial(T(7)) == 5040
           @test Core.Compiler.is_foldable(Base.infer_effects(factorial, (T,)))
       end
       end

[...]
Test Summary: | Pass  Fail  Total  Time
test set      |   10    10     20  0.4s
  T = Int128  |    1     1      2  0.0s
  T = Int16   |    1     1      2  0.0s
  T = Int32   |    1     1      2  0.0s
  T = Int64   |    1     1      2  0.0s
  T = Int8    |    1     1      2  0.0s
  T = UInt128 |    1     1      2  0.0s
  T = UInt16  |    1     1      2  0.0s
  T = UInt32  |    1     1      2  0.0s
  T = UInt64  |    1     1      2  0.0s
  T = UInt8   |    1     1      2  0.0s
ERROR: Some tests did not pass: 10 passed, 10 failed, 0 errored, 0 broken.

(run on a ~month old master, hence the failures)

@test factorial(0) == 1
@test_throws DomainError factorial(-1)
@test factorial(Int64(20)) == 2432902008176640000
Expand Down