Skip to Content
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!

23 Comments
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

  • 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!

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

    /
    🤷‍♂️
    • 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.

        • 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

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

         

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

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

    /
    Program%20output
  • 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