1

I kindly request those who think this question have been asked earlier, read on first.

I need to print all armstrong numbers between 1 and 10000. My problem is that whenever my program is run and reaches 150, it does

(1^3) + ((5^3)-1) + (0^3)

instead of

(1^3) + (5^3) + (0^3).

Thus it does not print 153 (which is an Armstrong number), of course because the sum results in 152. I do not know if some other numbers are also doing this. But i do have checked untill 200 and there is no problem with other numbers except that in 150–160 range.

Is this a compiler error. Should i re-install my compiler? Currently i am using codeblocks.

#include <iostream>
#include <math.h>

using namespace std;

int main()
{
    for(int i = 0;i <= 10000;++i)
    {
        int r = i;
        int dig = 0;
        while(r != 0)
        {
            dig++;
            r /= 10;
        }
        int n = i, sum = 0;
        while(n != 0)
        {
            int d = n % 10;
            sum += pow(d, dig);
            n /= 10;
        }
        if(sum == i)
            cout << i << ' ';
    }
    cout << "\n\n\n";
    return 0;
}
Martin Ueding
  • 8,245
  • 6
  • 46
  • 92
Sri
  • 53
  • 5

3 Answers3

1

You should run your code in the debugger. Also your code does not compile for me (GCC 6) because you use cout without std:: or using namespace std;. So how does it compile on your system? You are also using math.h, in C++ you should rather use cmath.

After fixing this, I get the following output on my Fedora 24 with g++ in version 6.4.1:

0 1 2 3 4 5 6 7 8 9 153 370 371 407 1634 8208 9474

The 153 is included in there, so either your compiler has an error or your program has undefined behavior and therefore the error ensues.

I have looked at the definition for Armstrong numbers and did a really short Python implementation:

# Copyright © 2017 Martin Ueding <dev@martin-ueding.de>
# Licensed under the MIT/Expat license.

def is_armstrong(number):
    digits = [int(letter) for letter in str(number)]
    score = sum(digit**len(digits) for digit in digits)
    return score == number

armstrong = list(filter(is_armstrong, range(10000)))
print(' '.join(map(str, armstrong)))

The output matches your C++ program on my machine exactly:

0 1 2 3 4 5 6 7 8 9 153 370 371 407 1634 8208 9474

Looking through your code I cannot spot undefined behavior, it looks sensible. First you count the number of digits, then you build up the sum. Perhaps you should try with other compilers like GCC, LLVM, or Ideone. Does Code Blocks ship their own compiler or do they use a system compiler? What operating system are you running?


You said that you are just learning to program. That's cool to hear! I hope you have a good C++ book or other resource. For C++, there is a lot of bad advice on the internet. Also make sure that you have a book that has at least C++11, everything else is badly outdated.

I have changed your program and created some short functions that do just one task such that it is easier to read and reason about. I am not sure whether you already know about functions, so don't worry if that seems to complicated for now :-).

#include <cmath>
#include <iostream>

int get_digit_count(int const number) {
    int digits = 0;
    int remainder = number;

    while (remainder > 0) {
        ++digits;
        remainder /= 10;
    }

    return digits;
}

bool is_armstrong_number(int const number) {
    int const digit_count = get_digit_count(number);
    int remainder = number;
    int sum = 0;

    while (remainder > 0) {
        int const last_digit = remainder % 10;
        sum += std::pow(last_digit, digit_count);
        remainder /= 10;
    }

    return number == sum;
}

int main() {
    for (int i = 0; i <= 10000; ++i) {
        if (is_armstrong_number(i)) {
            std::cout << i << ' ';
        }
    }
    std::cout << std::endl;
}
Martin Ueding
  • 8,245
  • 6
  • 46
  • 92
  • thank you Martin. firstly, i use windows 8.1. i am just in the early learning stages of programming languages so i do not really know if they ship their compiler or something like that. so, sorry. i actually have include _using namespace std_. but i forgot to mention earlier. so, sorry for that too. i do not know, but when i put a loop and a variable for the pow() exponent, it does not work. it gives the above _-1_ result again. so maybe compiler problem. i'll probably reinstall it or other compiler. Thank you a lot. – Sri Aug 20 '17 at 09:55
  • What do you mean with “loop and variable for the `pow` exponent”? In your example, the `pow` gets `dig` passed as the second parameter, and that is a variable. – Martin Ueding Aug 20 '17 at 10:55
  • i mean when i use pow(5, 3) for _sum_, it gives 153. but when i use a variable instead of _3_ above and put a loop to find _dig_, pow(5, dig) when put in sum gives 152. and with all respect, i find it really difficult to work with function, suppose its because i'm just starting to learn c++. but thanks dude. – Sri Aug 20 '17 at 11:19
  • I suggest that you do a `cout << "i = " << i << ", dig = " << dig << endl;` between the two `while` loops. That way you can check whether `dig` is indeed `3` when `i == 153`. It is really strange, and I still do not see where this could go wrong. — Don't worry if functions overwhelm you, go at a pace that is good for you. We all have started with small steps, no need to run before one can walk. :-) – Martin Ueding Aug 20 '17 at 13:12
  • yeah i did the same. the _cout_ one. that's how i came to know what the problem was. – Sri Aug 21 '17 at 09:37
0

This algorithm generates and prints out Armstrong numbers to 999, but can easily be expanded to any length using the same methodology.

n = 1;   %initialize n, the global loop counter, to 1

for i = 1 : 10   %start i loop

    for j = 1 : 10   %start j loop

        for k = 1 : 10   %start k loop

            rightnum = mod(n, 10);   %isolate rightmost digit

            midnum = mod(fix((n/10)), 10);   %isolate middle digit 

            leftnum = fix(n/100);   %isolate leftmost digit    

        if ((n < 10))   %calulate an for single-digit n's   
            an = rightnum;     
              end

        if ((n > 9) & (n < 100))   %calculate an for 2-digit n's
            an = fix(rightnum^2 + midnum^2);         
              end

        if ((n  > 99) & (n < 1000))   %calculate an for 3-digit n's
            an = fix(leftnum^3 + midnum^3 + rightnum^3);     
              end

            if (n == an)   %if n = an display n and an
                armstrongmatrix = [n an];
                disp(armstrongmatrix);
            end

        n = n + 1;   %increment the global loop counter and continue

        end
    end

end
eesiraed
  • 4,626
  • 4
  • 16
  • 34
0

You can use arrays:

#include<iostream>
using namespace std;
int pow(int, int);
int checkArm(int);
int main() {
    int range;
    cout<<"Enter the limit: ";
    cin>>range;
    for(int i{};i<=range;i++){
        if(checkArm(i))
            cout<<i<<endl;
    }
    return 0;
}
int pow(int base, int exp){
    int i{0};
    int temp{base};
    if(exp!=0)
        for(i;i<exp-1;i++)
            base = base * temp;
    else
        base=1;
    return base;
}
int checkArm(int num) {
    int ar[10], ctr{0};
    int tempDigits{num};
    while(tempDigits>0){
        tempDigits/=10;
        ctr++;
    }
    int tempArr{num}, tempCtr{ctr};
    for(int i{0};i<=ctr;i++){
        ar[i] = tempArr / pow(10,tempCtr-1);
        tempArr = tempArr % pow(10,tempCtr-1);
        tempCtr--;
    }
    int sum{};
    for(int k{};k<ctr;k++){
        sum+=pow(ar[k],ctr);
    }
    if(sum==num)
        return 1;
    else
        return 0;
}