Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:Fit Binominal calculate.cpp to guidelines #2464

Closed
wants to merge 12 commits into from
81 changes: 50 additions & 31 deletions math/binomial_calculate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,76 @@
* @brief Program to calculate [Binomial
* coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient)
*
* @details
* quoted from: [Weisstein, Eric W. "Binomial Coefficient." From MathWorld--A
* Wolfram Web
* Resource.](https://mathworld.wolfram.com/BinomialCoefficient.html) "The
* binomial coefficient \f$ \binom{n}{k} \f$ is the number of ways of picking \f$k\f$ unordered
* outcomes from \f$n\f$ possibilities, also known as a combination or combinatorial
* number. The symbols \f$ _nC_k \f$ and \f$ \binom{n}{k} \f$ are used to
* denote a binomial coefficient, and are sometimes read as "n choose k." \f$ \binom{n}{k} \f$
* therefore gives the number of k-subsets possible out of a set of n distinct
* items. For example, The 2-subsets of {1,2,3,4} are the six pairs {1,2},
* {1,3}, {1,4}, {2,3}, {2,4}, and {3,4}, so \f$ \binom{4}{2} =6.\f$"
* [Another good example/explanation](https://math.stackexchange.com/questions/2172355/probability-notation-two-numbers-stacked-inside-brackets)
*
* @note An identity of the binomial coefficient is \f$ \binom{n}{n-k} \f$ This is explained
* partially in the comments of this implementation but in more detail at [Prof.
* Tesler: Chapter 3.3, 4.1, 4.3. Binomial Coefficient
* Identities](https://mathweb.ucsd.edu/~gptesler/184a/slides/184a_ch4slides_17-handout.pdf
* page 2)
*
* @author [astronmax](https://github.com/astronmax)
*/

#include <cassert> /// for assert
#include <cstdint> /// for int32_t type
#include <cstdlib> /// for atoi
#include <iostream> /// for IO operations

/**
* @namespace math
* @brief Mathematical algorithms
*/
namespace math {
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
/**
*
* @namespace binomial
* @brief Functions for [Binomial
* coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient)
* implementation
*/
namespace binomial {
namespace math { namespace binomial {
ewd00010 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

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

this needs to be documented as well

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
namespace math { namespace binomial {
namespace math {
namespace binomial {

/**
* @brief Function to calculate binomial coefficients
* @param n first value
* @param k second value
* @return binomial coefficient for n and k
* @param n number of possibilities
* @param k size of subset
* @return n if k == 1
* @return 1 if k == 0
* @return result if k != 0 || 1
*/
size_t calculate(int32_t n, int32_t k) {
// basic cases
if (k > (n / 2))
k = n - k;
if (k == 1)
return n;
if (k == 0)
/*!
* Why do we do if k > (n/2) then k = n-k? Because \f$ \binom{n}{k} \f$ is the same as
* \f$ \binom{n}{n-k} \f$ or, in this case, \f$ \binom{6}{4} \f$ is the same as \f$ \binom{6}{2} \f$ since both are
* calculated for \f$ n!/k!(n-k)! \f$, in this case \f$ 6!/4!2! \f$. By replacing \f$ k \f$ with
* \f$ n-k \f$ we get \f$ 6!/2!4! \f$ which is the same sum. the benefit however, is our
* loop further on in this implementation now requires less iterations to
* find the same answer.
*
* k == 1 and k == 0 follow the same rule as \f$ n^1 \f$and \f$ n^0 \f$ respectively
*/
if (k == 0) {
return 1;
} else if (k == 1) {
return n;
} else if (k > (n / 2)) {
k = n - k;
}

/*!
* (n - k) + i returns 1 higher each loop imitating a factorial calculation.
* Then imagine i as the size of each set, divide by it to find the amount
* of possible sets in result amount of possibilities
*/
size_t result = 1;
for (int32_t i = 1; i <= k; ++i) {
result *= n - k + i;
result *= (n - k) + i;
result /= i;
}

Expand All @@ -54,7 +86,6 @@ size_t calculate(int32_t n, int32_t k) {
* @returns void
*/
static void tests() {
// tests for calculate function
assert(math::binomial::calculate(1, 1) == 1);
assert(math::binomial::calculate(57, 57) == 1);
assert(math::binomial::calculate(6, 3) == 20);
Expand All @@ -66,27 +97,15 @@ static void tests() {
assert(math::binomial::calculate(60, 30) == 118264581564861424);
assert(math::binomial::calculate(62, 31) == 465428353255261088);

std::cout << "[+] Binomial coefficients calculate test completed"
std::cout << "Binomial coefficients tests successfully passed"
<< std::endl;
}

/**
* @brief Main function
* @param argc commandline argument count
* @param argv commandline array of arguments
* @returns 0 on exit
*/
int main(int argc, const char* argv[]) {
int main() {
tests(); // run self-test implementations

if (argc < 3) {
std::cout << "Usage ./binomial_calculate {n} {k}" << std::endl;
return 0;
}

int32_t n = atoi(argv[1]);
int32_t k = atoi(argv[2]);

std::cout << math::binomial::calculate(n, k) << std::endl;
return 0;
}