Skip to content

Commit c663926

Browse files
authored
Check overflow in multinomial (#172)
* Check overflow in `multinomial` * test multinomial throw * test: add special case test for multinomial * avoid use internal method * Update doc for multinomial
1 parent 9fef104 commit c663926

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

src/factorials.jl

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,42 @@ end
9595
"""
9696
multinomial(k...)
9797
98-
Multinomial coefficient where `n = sum(k)`.
98+
Compute the multinomial coefficient
99+
``\\binom{n}{k_1,k_2,...,k_i} = \\frac{n!}{k_1!k_2! \\cdots k_i!}, n = \\sum{k_i}``.
100+
Throws an `OverflowError` when the input is too large.
101+
102+
See Also: `binomial`.
103+
104+
# Examples
105+
```jldoctest
106+
julia> # (x+y)^2 = x^2 + 2xy + y^2
107+
108+
julia> multinomial(2, 0)
109+
1
110+
111+
julia> multinomial(1, 1)
112+
2
113+
114+
julia> multinomial(0, 2)
115+
1
116+
117+
julia> multinomial(10, 10, 10, 10)
118+
ERROR: OverflowError: 5550996791340 * 847660528 overflowed for type Int64
119+
Stacktrace:
120+
[...]
121+
```
122+
123+
# External links
124+
- [Definitions](https://dlmf.nist.gov/26.4.2) on DLMF
125+
- [Multinomial theorem](https://en.wikipedia.org/wiki/Multinomial_theorem) on Wikipedia
99126
"""
100127
function multinomial(k...)
101128
s = 0
102129
result = 1
103130
@inbounds for i in k
104131
s += i
105-
result *= binomial(s, i)
132+
bi = binomial(s, i)
133+
result = Base.Checked.checked_mul(result, bi)
106134
end
107135
result
108136
end

test/factorials.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,22 @@
3131
@test multifactorial(40, 2) == doublefactorial(40)
3232
@test_throws DomainError multifactorial(-1, 1)
3333

34-
# multinomial
35-
@test multinomial(1, 4, 4, 2) == 34650
34+
@testset "multinomial" begin
35+
# > For k=0,1, the multinomial coefficient is defined to be 1
36+
# https://dlmf.nist.gov/26.4#i.p1
37+
@test multinomial() == 1
38+
@test multinomial(0) == 1
39+
40+
@test multinomial(1, 4, 4, 2) == 34650
41+
# wolfram: Multinomial[10, 10, 10, 5]
42+
@test multinomial(10, 10, 10, 5) == 1_802_031_190_366_286_880
43+
44+
# checked_mul overflowed for type Int64
45+
@test_throws OverflowError multinomial(10, 10, 10, 6)
46+
@test_throws OverflowError multinomial(10, 10, 10, 10)
47+
# binomial(200, 100) overflows
48+
@test_throws OverflowError multinomial(100, 100)
49+
end
3650

3751
# primorial
3852
@test primorial(17) == 510510

0 commit comments

Comments
 (0)