
/**
 * Partitions an integer `num` into `div` summands and returns the `i`th
 * of the partition.
 *
 * @param num Integer to be partitioned
 * @param div Number of partitions
 * @param i Index of partition
 *
 * @example
 * num = 17
 * div = 5
 *
 * partition(17, 5, 0) -> 4
 * partition(17, 5, 1) -> 4
 * partition(17, 5, 2) -> 3
 * partition(17, 5, 3) -> 3
 * partition(17, 5, 5) -> 3
 *
 * 17 = num = div * num + num % div = 4 + 4 + 3 + 3 + 3
 *                                   1st 2nd 3rd 4th 5th
 *                                   i=0 i=1 i=2 i=3 i=4
 */
int partition(int num, int div, int i) {
    return num / div + static_cast<int>(i < (num % div));
}

/**
 * Computes the partial sum of the first `i` integer `num` partitioned into
 * `div` parts using `partition()`.
 *
 *      sum_{j = 0}^i partition(num, div, j).
 *
 * @param num Integer to be partitioned
 * @param div Number of partitions
 * @param i Index of partition
 *
 * @example
 * num = 17
 * div = 5
 *
 * partition_sum(17, 5, 0) -> 4
 * partition_sum(17, 5, 1) -> 8
 * partition_sum(17, 5, 2) -> 11
 * partition_sum(17, 5, 3) -> 14
 * partition_sum(17, 5, 5) -> 17
 */
int partition_sum(int num, int div, int i) {
    int sum = 0;
    for (int j = 0; j <= i; ++j) {
        sum += partition(num, div, j);
    }
    return sum;
}

/**
 * Factorized a integer number `num` into two multiplicative factors.
 * These factors are as close together as possible. This means for example for
 * square numbers that the two factors are the square root of `num`.
 *
 * Assumes small numbers and therefore uses a simple linear search.
 *
 * The first few integers are factorized as follows:
 *
 *   0 = 1 * 0
 *   1 = 1 * 1
 *   2 = 1 * 2      (is prime)
 *   3 = 1 * 3      (is prime)
 *   4 = 2 * 2      (is square)
 *   5 = 1 * 5      (is prime)
 *   6 = 2 * 3
 *   7 = 1 * 7      (is prime)
 *   8 = 2 * 4
 *   9 = 3 * 3      (is square)
 *  10 = 2 * 5
 *  11 = 1 * 11     (is prime)
 *  12 = 3 * 4
 *  13 = 1 * 13     (is prime)
 *  14 = 2 * 7
 *  15 = 3 * 5
 *  16 = 4 * 4      (is square)
 *
 * @param num integer to be factorized
 * @param factor [out] output parameter of length 2 where the two factors are
 *  written into.
 *
 * @example
 * int factors[2];
 * two_factors(15, factors);    // -> factors = {3, 5}
 */
void two_factors(int num, int* factors) {
    // In case of zero, set both to zero
    if (!num) {
        factors[0] = factors[1] = 0;
    }

    // Ensure `num` is positive
    if (num < 0) {
        num *= -1;
    }

    // Set initial factorization (this always works)
    factors[0] = 1;
    factors[1] = num;

    // Check all numbers `i` until the integer square-root
    for (int i = 2; i * i <= num; ++i) {
        // Check if `i` is a divisor
        if (!(num % i)) {
            // Update factors as `i` divides `num`
            factors[0] = i;
            factors[1] = num / i;
        }
    }
}
