###### Personal Insights # Another ABAP puzzle – Narcissistic numbers

About two weeks ago, I posted this about FizzBuzz in ABAP, and solving programming puzzles. It seems it was well received, so here’s another one that may or may not be simple to solve.

## Narcissistic numbers

In number theory, a narcissistic number is a number where the sum of each of its digits raised to the power of the total number of digits equals the number itself. This is the case for instance for the number 153. It has 3 digits, so when each digit is raised to the power 3, then the sum equals 153.

1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153

(Narcissistic numbers are also known as Armstrong numbers or plus perfect numbers.)

The suggested task here is to implement a program that lists all narcissistic numbers with 5 or less digits, i.e. between 0 and 99999.

These are, for reference 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748, 92727 and 93084

I have made some examples solution and posted in this ABAP puzzle repository.

Have fun, and enjoy your process!

### Assigned Tags

You must be Logged on to comment or reply to a post. Hi Jörgen,

nice challenge - especially because I haven't solved it yet. Will give it a try in the coming days and once solved have a look at your solutions 😉

Cheers

Hendrik Jörgen Lindqvist
Blog Post Author

Lovely! Hope you enjoy it! Nice ... Interesting puzzle!

Here is something that I have tried. It is similar to your solution, except I have stored the powers of all numbers from 1 to 9 in internal tables and used a dynamic read statement to get the powers during summation.

My solution

Let me know what you think! Jörgen Lindqvist
Blog Post Author

That's a creative and overly complex solution. Love that, thank you for sharing. I'll add a link to your solution from my repository as well! Here goes my solution:

``````types TT_NUMBER type sorted table of I with unique key TABLE_LINE.
data(ARMSTRONG_NUMBERS)
= value TT_NUMBER(
for N = 0 while N < 100000
for M = 1
while M = 1
and N = reduce I(
let STR = |{ N }|
LEN = STRLEN( STR ) in
init SUM = 0
for OFF = 0 while OFF < LEN
next SUM += IPOW( BASE = STR+OFF(1) EXP = LEN ) )
( N ) ).``````

Few points about the solution:

• The solution uses string operations to find out the digits of the number. Similar to your solution 2
• The first iteration (for N) just generates the number sequentially
• The second iteration (for M) runs once and evaluates the sum of the powers of the digits of N

PS - I cannot create a pull request for the repo. Am i doing something wrong?  Jörgen Lindqvist
Blog Post Author

Oh, nice one Suhas Saha with the reduce!

You probably need to create a branch of the repository, add your changes there, and then create a pull request for that branch. Or did you do that already? I'm not that well versed in Git...

Otherwise, I'll happily add your solution in there... I cannot create a branch 🤦‍♂️ Pretty sure i am doing something wrong, i am n00b when it comes to Git.

If you think that my solution deserves to be in your list, please add it. Jörgen Lindqvist
Blog Post Author

I added a link to your solution in the repository.

And I realized also that you can not create a branch there. You would have needed to FORK to a repository of your own, then make your changes there, and create a pull request for your fork...

https://docs.github.com/en/github/getting-started-with-github/fork-a-repo Thanks Jörgen Lindqvist

I had initially thought of forking your repo too, but wasn't sure if it was right way. Just saw that Jacques Nomssi Nzali had created a fork of his own. I am learning something new about Git every day.

But honestly why can't i create a branch? 🤔 Any pointers Lars Hvam ? Jörgen Lindqvist
Blog Post Author

It would be the right thing. Since it's "my" repository, you don't have write access to it, and therefore can not create branches in there. That's why you instead need to create a fork into your own repository, where you have write access... Hi Suhas, did you run this as an ABAP program? It doesn't output anything. Also my ABAP does not accept your syntax "+=". Is this a higher version which accepts this syntax. I am on 750. Would be interesting to see your output if it is working. Hi Martin,

Yes, i did execute my solution before posting it here.

As per the documentation, the assignment operators +=, -= et al. are available since release 754. You can replace SUM += IPOW(... with SUM = SUM + IPOW(... to check if it runs on your ABAP release.

This was just the algorithm to get the numbers. The complete solution is posted here. Thanks Suhas. I took a look at the documentation you referenced and your more extended solution. Very good. DATA number TYPE string VALUE '99999'.
DATA sum TYPE int8.

WHILE number >= 0.

CONDENSE number.
DATA(number_lengthstrlennumber ).

DATA(counter0.

WHILE counter < number_length.
sum += number+counter(1** number_length.
counter += 1.
ENDWHILE.

IF sum number.
WRITE number.
ENDIF.

number -1.
sum 0.

ENDWHILE. Jörgen Lindqvist
Blog Post Author

Thanks for sharing!

You used the type conversions from string to number, I used from number to string. I like how many ways there are to do the same thing... 👍 Arnold did you run this code in an ABAP system? My ABAP Editor did not accept your += and -= syntax. It would be great to see your program output from a screen capture. Hi Martin ,

For the reason that your GUI Version might be lower than 7.50-7.60, the syntax += and -= is not recognized.

You can use

• sum = sum + ( number+counter(1** number_length ) instead of the existing code
• counter = counter + 1 instead of counter += 1
• number = number - 1 instead of number -1

I can not send a capture right now, I am having problems with uploading an image here, but apply the changes that I explained above and you will have a functining report too.

Regards

Arnold Lol. I know how to add and subtract in ABAP Arnold. Thanks. I was just curious, I had always wanted this syntax in ABAP now I know it is available in a future version. Still don't know why they didn't go for the universally recognised C++ syntax of my_var++ or my_var--. Hi Jörgen, I thought I would give this a try. It was surprisingly tricky.

``````DATA: lv_offset     TYPE i,
lv_multiplier TYPE i.
WRITE: / `0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748, 92727, 93084`,
/ .
DATA(lv_loop) = 0 . "start from 0
DO 99999 TIMES.
lv_answer = lv_f_answer = lv_offset = 0 .
DATA(lv_char) = |{ lv_loop }| .
DATA(lv_exponent) = strlen( lv_char ) . "exponent and length
DO lv_exponent TIMES.
lv_multiplier = lv_char+lv_offset(1) .
lv_answer = lv_multiplier ** lv_exponent .
lv_offset = lv_offset + 1 .
ENDDO.
IF lv_f_answer = lv_loop .
WRITE: CONV string( lv_f_answer ) .
ENDIF.
lv_loop = lv_loop + 1 .
ENDDO.``````

Here is the output. The first line is the reference result and the program output is below that. Program output

Regards, Martin. Jörgen Lindqvist
Blog Post Author

Thanks for sharing, Martin Coetzee! Yes there is some hidden 'trickiness' in this one... 😊 Hey Jörgen,

Interesting puzzle, I notice nobody tried the recursive approach so had a go. I am also trying to use immutable data rather than changing variables.

Full source is here , core logic below:

``````CLASS lcl_narcissist IMPLEMENTATION.

METHOD run.
check( i_number = 0
i_sum_of_powers = 0
i_pos = i_length ).
ENDMETHOD.

METHOD check.
CHECK i_sum_of_powers <= i_number.  "Performance

DO 10 TIMES.
DATA(digit) = sy-index - 1.

IF i_pos > 1.
check( i_number = i_number + digit * 10 ** ( i_pos - 1 )
i_sum_of_powers = i_sum_of_powers + digit ** power
i_pos = i_pos - 1 ).

IF power < i_pos.
power = i_pos.
ENDIF.

ELSE.
IF i_number + digit = i_sum_of_powers + digit ** power.
WRITE |{ i_number + digit } |.
ENDIF.
ENDIF.

ENDDO.

ENDMETHOD.

ENDCLASS.
``````

Regards,
Mike Jörgen Lindqvist
Blog Post Author

Awesome. Thanks for sharing, I love this.

Totally different solution from all the others. 😊