0

I am trying to print out the first few numbers that follow a certain rule: the sum of its digits can be raised to an integral power to get the number itself. (Basically if the sum is an nth root of the number).

For example, the sum of the digits in the number 81 is 9, and 9^2 is 81.

This is some of the code I am using:

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <math.h>
using namespace std;

int sumOfDigits(int num) {
    int sum = 0;
    string numStr = "";
    stringstream s;
    s << num;
    s >> numStr;
    for (int i = 0; i < numStr.length(); i++) {
        int ad = 0;
        stringstream ss;
        ss << numStr[i]; // take each digit
        ss >> ad;
        sum += ad; // and add to sum
    }
    return sum;
}

int num = 10; // starting number
int numFound = 0; // how many such special numbers have been found

int main() {
    while (numFound < 5) {
        int sum = sumOfDigits(num);
        double exp = log10(num) / log10(sum);

        if (fmod(exp, 1.0) == 0.0 && sum != 1) { // if the exponent is an integer
            cout << num << "\t" << sum << endl; // then print out the number and the sum of its digits
            numFound++;
        }
        num++;
    }

    return 0;
}

When I run this, I get the following output:

81      9
2401    7
4913    17
5832    18
17576   26

The second entry should be 512 and 8 because 8^3 is 512. I don't understand why the test works with some numbers but doesn't work with others.

I've tried other methods of testing whether the exponent is an integer as well. I've tested it against the floor() expression, and I've tried casting the entire expression with (int).

I may be wrong and the problem may not be in that spot, but I would really appreciate it if you could help me with this. Thank you.

Beöbe
  • 69
  • 7
  • `log10(num) / log10(sum)` => `log(num) / log(sum)` would be much faster because log of any bases will be calculated based on natural log internally – phuclv Jun 06 '17 at 03:27
  • When working with integers it is best to stay within the integer domain instead of converting to floating point. Roundoff errors can be a pain. A different algorithm would be required in this case. – Mark Ransom Jun 06 '17 at 04:30

2 Answers2

1

Checking for equality between floating point numbers like this: fmod(exp, 1.0) == 0.0 is bound to cause you trouble. For example, by simply changing your code like this:

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <math.h>
#include <limits>
using namespace std;

int sumOfDigits(int num) {
    int sum = 0;
    string numStr = "";
    stringstream s;
    s << num;
    s >> numStr;
    for (int i = 0; i < numStr.length(); i++) {
        int ad = 0;
        stringstream ss;
        ss << numStr[i]; // take each digit
        ss >> ad;
        sum += ad; // and add to sum
    }
    return sum;
}

int num = 10; // starting number
int numFound = 0; // how many such special numbers have been found

int main() {
    while (numFound < 5) {
        int sum = sumOfDigits(num);
        double exp = log10(num) / log10(sum);

        if (fabs(fmod(exp, 1.0)) < std::numeric_limits<float>::epsilon() && sum != 1) { // if the exponent is an integer
            //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            cout << num << "\t" << sum << endl; // then print out the number and the sum of its digits
            numFound++;
        }
        num++;
    }

    return 0;
}

I can get this output:

81  9
512 8
2401    7
4913    17
5832    18

So, use a suitable epsilon value or just stick to integers.

Read here:

What is the most effective way for float and double comparison?

nakiya
  • 14,063
  • 21
  • 79
  • 118
  • When I run this, it throws an error at the if statement: `invalid operands to binary expression ('double' and 'type (*)() throw()' (aka 'float (*)() throw()')) if (fabs(fmod(exp, 1.0)) < std::numeric_limits::epsilon &...` What can I do to fix this? Sorry I'm somewhat new to c++. – Beöbe Jun 06 '17 at 12:42
  • @Beöbe : Edited the code. Was missing parentheses after epsilon. – nakiya Jun 06 '17 at 16:58
0

It would be a lot faster to loop over sums and exponents:

unsigned int number;
unsigned int min_sum =   3;
unsigned int max_sum = 100;
unsigned int min_exp =   2;
unsigned int max_exp =  20;

int main() {
    for (unsigned int exp = min_exp; exp <= max_exp; ++exp) 
        for (unsigned int sum = min_sum; sum <= max_sum; ++sum) {
            number = pow(sum, exp);
            if ( sumOfDigits(number) == sum ) 
                cout << numFound++ << ":\t" << number << "\t = " << sum << " ^ \t" << exp << endl;
        }
    return 0;
}
  • This is an interesting approach. Definitely would be a lot faster. Thanks for mentioning it! – Beöbe Jun 06 '17 at 17:07