Browse Source

Math: add binomial coefficient function.

pull/435/merge
janos 6 years ago committed by Vladimír Vondruš
parent
commit
8013afc28c
  1. 2
      src/Magnum/CMakeLists.txt
  2. 18
      src/Magnum/Math/Functions.cpp
  3. 12
      src/Magnum/Math/Functions.h
  4. 27
      src/Magnum/Math/Test/FunctionsTest.cpp

2
src/Magnum/CMakeLists.txt

@ -111,11 +111,11 @@ set(MagnumMath_SRCS
Math/Angle.cpp Math/Angle.cpp
Math/Color.cpp Math/Color.cpp
Math/Half.cpp Math/Half.cpp
Math/Functions.cpp
Math/Packing.cpp Math/Packing.cpp
Math/instantiation.cpp) Math/instantiation.cpp)
set(MagnumMath_GracefulAssert_SRCS set(MagnumMath_GracefulAssert_SRCS
Math/Functions.cpp
Math/PackingBatch.cpp) Math/PackingBatch.cpp)
# Objects shared between main and math test library # Objects shared between main and math test library

18
src/Magnum/Math/Functions.cpp

@ -23,6 +23,8 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <Corrade/Utility/Assert.h>
#include "Functions.h" #include "Functions.h"
namespace Magnum { namespace Math { namespace Magnum { namespace Math {
@ -41,4 +43,20 @@ UnsignedInt log2(UnsignedInt number) {
return log; return log;
} }
UnsignedLong binomialCoefficient(UnsignedInt n, UnsignedInt k) {
if (k > n) return 0;
if (k * 2 > n)
k = n-k;
if (k == 0) return 1;
UnsignedLong result = n;
for(UnsignedInt i = 2; i <= k; ++i ) {
CORRADE_ASSERT(result < ~UnsignedLong{} / (n-i+1), "Math::binomialCoefficient(): overflow for (" << Corrade::Utility::Debug::nospace << n << "choose" << k << Corrade::Utility::Debug::nospace << ")", 0ul);
result *= (n-i+1);
result /= i;
}
return result;
}
}} }}

12
src/Magnum/Math/Functions.h

@ -410,6 +410,18 @@ template<std::size_t size, class T> inline Vector<size, T> ceil(const Vector<siz
return out; return out;
} }
/**
@brief [Binomial Coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient)
Returns the number of combinations of @f$ n @f$ things taken @f$ k @f$ at a time.
The number of ways to do this is given by
@f[
\begin{pmatrix} n \\ k \end{pmatrix} = \frac{n! \cdot (n-k)!}{k!} = \frac{n \cdot (n-1) \cdots (n - k + 1)}{k \cdots 1}.
@f]
*/
UnsignedLong MAGNUM_EXPORT binomialCoefficient(UnsignedInt n, UnsignedInt k);
/** /**
@brief Floating point division remainder @brief Floating point division remainder
@param a Numerator @param a Numerator

27
src/Magnum/Math/Test/FunctionsTest.cpp

@ -53,6 +53,9 @@ struct FunctionsTest: Corrade::TestSuite::Tester {
void ceil(); void ceil();
void fmod(); void fmod();
void binomialCoefficient();
void binomialCoefficientOverflow();
void sqrt(); void sqrt();
void sqrtInverted(); void sqrtInverted();
void lerp(); void lerp();
@ -115,6 +118,9 @@ FunctionsTest::FunctionsTest() {
&FunctionsTest::ceil, &FunctionsTest::ceil,
&FunctionsTest::fmod, &FunctionsTest::fmod,
&FunctionsTest::binomialCoefficient,
&FunctionsTest::binomialCoefficientOverflow,
&FunctionsTest::sqrt, &FunctionsTest::sqrt,
&FunctionsTest::sqrtInverted, &FunctionsTest::sqrtInverted,
&FunctionsTest::lerp, &FunctionsTest::lerp,
@ -293,6 +299,27 @@ void FunctionsTest::ceil() {
CORRADE_COMPARE(Math::ceil(2.7_degf), 3.0_degf); CORRADE_COMPARE(Math::ceil(2.7_degf), 3.0_degf);
} }
void FunctionsTest::binomialCoefficient() {
CORRADE_COMPARE(Math::binomialCoefficient(1, 1), 1ul);
CORRADE_COMPARE(Math::binomialCoefficient(1, 0), 1ul);
CORRADE_COMPARE(Math::binomialCoefficient(19, 11), 75582ul);
CORRADE_COMPARE(Math::binomialCoefficient(1000, 999), 1000ul);
CORRADE_COMPARE(Math::binomialCoefficient(0, 0), 1ul);
CORRADE_COMPARE(Math::binomialCoefficient(32, 11), 129024480ul);
CORRADE_COMPARE(Math::binomialCoefficient(62, 31), 465428353255261088ul);
}
void FunctionsTest::binomialCoefficientOverflow() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
std::ostringstream out;
Error redirectError{&out};
Math::binomialCoefficient(63, 31);
CORRADE_COMPARE(out.str(), "Math::binomialCoefficient(): overflow for (63 choose 31)\n");
}
void FunctionsTest::fmod() { void FunctionsTest::fmod() {
CORRADE_COMPARE(Math::fmod(5.1f, 3.0f), 2.1f); CORRADE_COMPARE(Math::fmod(5.1f, 3.0f), 2.1f);
CORRADE_COMPARE(Math::fmod(Vector3(5.1f, -5.1f, 6.8f), Vector3(3.0f, 3.0f, 1.1f)), Vector3(2.1f, -2.1f, 0.2f)); CORRADE_COMPARE(Math::fmod(Vector3(5.1f, -5.1f, 6.8f), Vector3(3.0f, 3.0f, 1.1f)), Vector3(2.1f, -2.1f, 0.2f));

Loading…
Cancel
Save