How to generate numbers upto 18 digits, sum of whose reciprocals is a whole number [closed]

Some thoughts to get you started:

  • Your number can’t contain zeros.
  • You can always add ones to a valid number and it will still be valid.
  • You don’t need to generate numbers. Generate lists of digits instead. If you keep the list in ascending order, you will automatically solve to problem of how to eliminate permutations.
  • Each of the true fractions 1/2 to 1/9 can be represented as an expanded fraction with the common denominator 2520.

So the following approach might work:

  • Start with an empty array and the sum 0.
  • Now call your generating function recursively. In each recursion, check wether the sum is divisible by 2520 without remainder. If so, print that number, and also print all numbers padded with ones at the front until you have 18 digits. So for 236 print 236, 1236, 11236 and so on until 111 111 111 111 111 236.
  • If your array has length 18, don’t recurse further. Otherwise, call your function after adding each of the digits 2 to 9 to your list, but don’t use digits that are smaller than the last digit in the list to keep the list sorted.
  • Don’t recalculate the sum, but instead keep a running sum: When you recurse, add the corresponding numerator to the sum: 1260 for 2, 840 for 3, 630 for 4 and so on.

This bottom-up approach is a lot faster than examining all possible numbers. The following program will print all 14,137 valid numbers (unordered, i.e. in order of generation) in the fraction of a second:

#include <stdlib.h>
#include <stdio.h>

#define NDIGIT 18

void rec(int set[], int n, int sum)
{
    static int num[10] = {
        0, 2520, 1260, 840, 630, 504, 420, 360, 315, 280
    };

    if (sum % 2520 == 0) {
        for (int j = 0; j < NDIGIT - n + 1; j++) {
            for (int i = 0; i < j; i++) putchar('1');
            for (int i = 0; i < n; i++) putchar(set[i] + '0');
            putchar('\n');
        }
    }

    if (n < NDIGIT) {
        int i0 = n ? set[n - 1] : 2;

        for (int i = i0; i < 10; i++) {
            set[n] = i;
            rec(set, n + 1, sum + num[i]);
        }
    }
}

int main()
{
    int set[NDIGIT];

    rec(set, 0, 0);

    return 0;
}

If you need sorted output, convert the set to a long integer, perhaps uint64_t from <stdint.h> and store it in an array instead of printing them right away. Then sort the array and print the numbers.

Leave a Comment