Browse Source

untemplate binomial & and assert test

pull/461/head
janos 6 years ago
parent
commit
305b1a66e6
  1. 2
      src/Magnum/CMakeLists.txt
  2. 18
      src/Magnum/Math/Functions.cpp
  3. 24
      src/Magnum/Math/Functions.h
  4. 26
      src/Magnum/Math/Test/FunctionsTest.cpp

2
src/Magnum/CMakeLists.txt

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

18
src/Magnum/Math/Functions.cpp

@ -23,6 +23,8 @@
DEALINGS IN THE SOFTWARE.
*/
#include <Corrade/Utility/Debug.h>
#include "Functions.h"
namespace Magnum { namespace Math {
@ -41,4 +43,20 @@ UnsignedInt log2(UnsignedInt number) {
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;
}
}}

24
src/Magnum/Math/Functions.h

@ -34,7 +34,6 @@
#include <cstdlib> /* std::div() */
#include <type_traits>
#include <utility>
#include <limits>
#include <Corrade/Utility/StlMath.h>
#include "Magnum/visibility.h"
@ -413,30 +412,15 @@ template<std::size_t size, class T> inline Vector<size, T> ceil(const Vector<siz
/**
@brief Computes a Binomial Coefficient
@brief [Binomial Coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient)
Given n elements computes the number of ways to choose k elements
without replacement. The number of ways to do this is
given by
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]
*/
template<class T> inline typename std::enable_if<IsIntegral<T>::value, T>::type binomialCoefficient(T n, T k) {
CORRADE_ASSERT(k >= 0, "k must be positive to compute the Binomial Coefficient", T{0});
if (k > n) return 0;
if (k * 2 > n)
k = n-k;
if (k == 0) return 1;
T result = n;
for(T i = 2; i <= k; ++i ) {
CORRADE_ASSERT(result < std::numeric_limits<T>::max()/(n-i+1), "Overflow In Binomial Coefficient", T{0});
result *= (n-i+1);
result /= i;
}
return result;
}
UnsignedLong MAGNUM_EXPORT binomialCoefficient(UnsignedInt n, UnsignedInt k);
/**
@brief Floating point division remainder

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

@ -54,6 +54,7 @@ struct FunctionsTest: Corrade::TestSuite::Tester {
void fmod();
void binomialCoefficient();
void binomialCoefficientOverflow();
void sqrt();
void sqrtInverted();
@ -118,6 +119,7 @@ FunctionsTest::FunctionsTest() {
&FunctionsTest::fmod,
&FunctionsTest::binomialCoefficient,
&FunctionsTest::binomialCoefficientOverflow,
&FunctionsTest::sqrt,
&FunctionsTest::sqrtInverted,
@ -298,12 +300,24 @@ void FunctionsTest::ceil() {
}
void FunctionsTest::binomialCoefficient() {
CORRADE_COMPARE(Math::binomialCoefficient(1, 1), 1);
CORRADE_COMPARE(Math::binomialCoefficient(1, 0), 1);
CORRADE_COMPARE(Math::binomialCoefficient(19, 11), 75582);
CORRADE_COMPARE(Math::binomialCoefficient(1000, 999), 1000);
CORRADE_COMPARE(Math::binomialCoefficient(0, 0), 1);
CORRADE_COMPARE(Math::binomialCoefficient(32, 11), 129024480);
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() {

Loading…
Cancel
Save