Skip to Content
Personal Insights
Author's profile photo Jörgen Lindqvist

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

      23 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Hendrik Neumann
      Hendrik Neumann

      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

      Author's profile photo Jörgen Lindqvist
      Jörgen Lindqvist
      Blog Post Author

      Lovely! Hope you enjoy it!

      Author's profile photo S Abinath
      S Abinath

      Nice ...

      Author's profile photo Taha Frosh
      Taha Frosh

      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!

      Author's profile photo Jörgen Lindqvist
      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!

      Author's profile photo Suhas Saha
      Suhas Saha

      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? 🤷‍♂️

      Author's profile photo Jörgen Lindqvist
      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...

      Author's profile photo Suhas Saha
      Suhas Saha

      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.

      Author's profile photo Jörgen Lindqvist
      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

      Author's profile photo Suhas Saha
      Suhas Saha

      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 ?

      Author's profile photo Jörgen Lindqvist
      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...

      Author's profile photo Martin Coetzee
      Martin Coetzee

      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.

      Author's profile photo Suhas Saha
      Suhas Saha

      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.

       

      Author's profile photo Martin Coetzee
      Martin Coetzee

      Thanks Suhas. I took a look at the documentation you referenced and your more extended solution. Very good.

      Author's profile photo Arnold Mirashi
      Arnold Mirashi

      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.

      Author's profile photo Jörgen Lindqvist
      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... 👍

      Author's profile photo Martin Coetzee
      Martin Coetzee

      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.

      Author's profile photo Arnold Mirashi
      Arnold Mirashi

      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

      Author's profile photo Martin Coetzee
      Martin Coetzee

      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--.

      Author's profile photo Martin Coetzee
      Martin Coetzee

      Hi Jörgen, I thought I would give this a try. It was surprisingly tricky.

      DATA: lv_offset     TYPE i,
            lv_answer     TYPE i,
            lv_f_answer   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_f_answer = lv_f_answer + lv_answer .
          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%20output

      Program output

      Regards, Martin.

      Author's profile photo Jörgen Lindqvist
      Jörgen Lindqvist
      Blog Post Author

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

      Author's profile photo Mike Pokraka
      Mike Pokraka

      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

      Author's profile photo Jörgen Lindqvist
      Jörgen Lindqvist
      Blog Post Author

      Awesome. Thanks for sharing, I love this.

      Totally different solution from all the others. 😊