Skip to content

Commit

Permalink
binomial(x,k) for non-integer x (#48124)
Browse files Browse the repository at this point in the history
* binomial(x,k) for non-integer x

* correct PR number in NEWS

* return 0 for k < 0

* comment on further generalizations
  • Loading branch information
stevengj authored Jan 24, 2023
1 parent 596ce65 commit f9d0473
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 2 deletions.
5 changes: 3 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ New library functions

New library features
--------------------
The `initialized=true` keyword assignment for `sortperm!` and `partialsortperm!`
is now a no-op ([#47979]). It previously exposed unsafe behavior ([#47977]).
* The `initialized=true` keyword assignment for `sortperm!` and `partialsortperm!`
is now a no-op ([#47979]). It previously exposed unsafe behavior ([#47977]).
* `binomial(x, k)` now supports non-integer `x` ([#48124]).

Standard library changes
------------------------
Expand Down
31 changes: 31 additions & 0 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1102,3 +1102,34 @@ Base.@assume_effects :terminates_locally function binomial(n::T, k::T) where T<:
end
copysign(x, sgn)
end

"""
binomial(x::Number, k::Integer)
The generalized binomial coefficient, defined for `k ≥ 0` by
the polynomial
```math
\\frac{1}{k!} \\prod_{j=0}^{k-1} (x - j)
```
When `k < 0` it returns zero.
For the case of integer `x`, this is equivalent to the ordinary
integer binomial coefficient
```math
\\binom{n}{k} = \\frac{n!}{k! (n-k)!}
```
Further generalizations to non-integer `k` are mathematically possible, but
involve the Gamma function and/or the beta function, which are
not provided by the Julia standard library but are available
in external packages such as [SpecialFunctions.jl](https://github.com/JuliaMath/SpecialFunctions.jl).
# External links
* [Binomial coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient) on Wikipedia.
"""
function binomial(x::Number, k::Integer)
k < 0 && return zero(x)/one(k)
# we don't use prod(i -> (x-i+1), 1:k) / factorial(k),
# and instead divide each term by i, to avoid spurious overflow.
return prod(i -> (x-(i-1))/i, OneTo(k), init=oneunit(x)/one(k))
end
8 changes: 8 additions & 0 deletions test/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,14 @@ end
for x in ((false,false), (false,true), (true,false), (true,true))
@test binomial(x...) == (x != (false,true))
end

# binomial(x,k) for non-integer x
@test @inferred(binomial(10.0,3)) === 120.0
@test @inferred(binomial(10//1,3)) === 120//1
@test binomial(2.5,3) 5//16 === binomial(5//2,3)
@test binomial(2.5,0) == 1.0
@test binomial(35.0, 30) binomial(35, 30) # naive method overflows
@test binomial(2.5,-1) == 0.0
end

# concrete-foldability
Expand Down

2 comments on commit f9d0473

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

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

Executing the daily package evaluation, I will reply here when finished:

@nanosoldier runtests(isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

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

Your package evaluation job has completed - possible new issues were detected.
A full report can be found here.

Please sign in to comment.