## Sunday, 23 June 2013

### Armstrong numbers

Armstrong (or Narcissistic) numbers are a special set of integers.

An n-digit number is an Armstrong number if the sum of the n-th power of the digits is equal to the original number. For example, 371 is an Armstrong number because the sum of 3 cubed, 7 cubed and 1 cubed is equal to 371.

Here we compute all the Armstrong numbers of 2, 3 and 4 digits.

• Power function
• ```# this subroutine returns the passed digit to the passed power
#
# inputs
#   r0 - digit
#   r1 - power
#
# outputs
#   r0 - digit ** power
#
# locals
#   r4
.globl _power
.align 2
.text
_power:
nop
stmfd sp!, {r4, lr}           @ save variables to stack

subs r1, r1, #1               @ leave unless power > 1
ble _power_end

mov r4, r0                    @ copy digit
_power_loop_start:
mul r0, r4, r0                @ raise to next power
subs r1, r1, #1
beq _power_end                @ leave when done
b _power_loop_start           @ next iteration
_power_end:
ldmfd   sp!, {r4, pc}         @ restore state from stack and leave subroutime
```
• Armstrong function
• ```# inputs
#   r0 - number
#
# outputs
#   r0 - armstrong number
#
# local r4, r5, r6, r7, r8

.equ ten,10
.equ hundred,100
.equ thousand,1000
.equ ten_thousand,10000

number .req r4
width .req r5
digit .req r6
current .req r7
armstrong .req r8

.globl _armstrong
.align 2
.text
_armstrong:
nop
stmfd   sp!, {r4, r5, r6, r7, r8, lr}          @ save variables to stack

mov     number, r0                             @ copy passed parameter to working number
cmp number, #ten                               @ exit unless number > 10
blt _end

ldr     current, =ten_thousand                 @ exit unless number < 10000
cmp number, current
bge _end

mov width, #0                                  @ initialise
mov digit, #0
mov armstrong, #0
ldr current, =thousand                         @ handle 1000 digit
_thousand_start:
cmp number, current
blt _thousand_end                              @ exit thousand code if none left

mov width, #4                                  @ width must be 4
add current, current, #thousand                @ bump thousand counter
add digit, digit, #1                           @ and corresponding digit count
b _thousand_start                              @ and loop
_thousand_end:
add number, number, #thousand                  @ need number modulo thousand
sub number, number, current
mov r0, digit                                  @ push digit
mov r1, width                                  @ and width
bl _power                                      @ to compute digit **width
add armstrong, r0, armstrong                   @ and update armstrong number with this value

ldr current, =hundred                          @ then we do the hundreds as we did the thousands
mov digit, #0
_hundred_start:
cmp number, current
blt _hundred_end

teq width, #0                                  @ and only set width if it is currently unset
moveq width, #3
_hundred_width:
b _hundred_start
_hundred_end:
sub number, number, current
mov r0, digit
mov r1, width
bl _power

ldr current, =ten                              @ then the tens as the hundred and thousands above
mov digit, #0
_ten_start:
cmp number, current
blt _ten_end

teq width, #0
moveq width, #2
_ten_width:
b _ten_start
_ten_end:
sub number, number, current
mov r0, digit
mov r1, width
bl _power

mov r0, number                                 @ then add in the trailing digits
mov r1, width
bl _power

mov r0, armstrong                              @ and copy the armstrong number back to r0 for return
_end:
ldmfd   sp!, {r4, r5, r6, r7, r8, pc}          @ restore state from stack and leave subroutine

```

We improve the legibility of the code by e.g. number .req r4. This textual substitution does increase the semantic value of the code considerably.

• Armstrong function with a macro to abstract repeated code
• N.B. This is functionally equivalent but much shorter than the previous function. The variable \@ here is a magic variable, incremented each time the macro is instantiated. This enables the use of distinct labels, which we need here.

```# inputs
#   r0 - number
#
# outputs
#   r0 - armstrong number
#
# local r4, r5, r6, r7, r8

.equ ten,10
.equ hundred,100
.equ thousand,1000
.equ ten_thousand,10000

number .req r4
width .req r5
digit .req r6
current .req r7
armstrong .req r8

.macro armstrong_digit a, b
ldr current, =\a
mov digit, #0
_start\@:
cmp number, current
blt _end\@

teq width, #0                                  @ and only set width if it is currently unset
moveq width, #\b
b _start\@
_end\@:
sub number, number, current
mov r0, digit
mov r1, width
bl _power
.endm

.globl _armstrong
.align 2
.text
_armstrong:
nop
stmfd   sp!, {r4, r5, r6, r7, r8, lr}          @ save variables to stack

mov     number, r0                             @ copy passed parameter to working number
cmp number, #ten                               @ exit unless number > 10
blt _end

ldr     current, =ten_thousand                 @ exit unless number < 10000
cmp number, current
bge _end

mov width, #0                                  @ initialise
mov armstrong, #0

armstrong_digit thousand 4
armstrong_digit hundred 3
armstrong_digit ten 2

mov r0, number                                 @ then add in the trailing digits
mov r1, width
bl _power

mov r0, armstrong                              @ and copy the armstrong number back to r0 for return
_end:
ldmfd   sp!, {r4, r5, r6, r7, r8, pc}          @ restore state from stack and leave subroutine

```

Here we introduce the use of the macro assembly functions of as Again this change leads to improved code - we eliminate duplication thus improving maintainability and legibility.

• Armstrong_main function
• ```.equ ten,10
.equ ten_thousand,10000

.section .rodata
.align 2
string:
.asciz "armstrong number of %d is %d\n"
.text
.align 2
.global main
.type main, %function
main:
ldr r5, =ten
ldr r6, =ten_thousand

_main_loop:
cmp r4, r6            @ leave if n = 10_000
beq _main_end

mov r0, r4            @ call the _armstrong function
bl _armstrong

teq r0, r4            @ if the armstong value = n print it
bne _main_next        @ else skip

mov r2, r0
mov r1, r4
ldr r0, =string       @ store address of start of string to r0
bl printf             @ call the c function to display information
_main_next:
b _main_loop
_main_end:
mov r7, #1            @ set r7 to 1 - the syscall for exit
swi 0                 @ then invoke the syscall from linux

```
• Result
• ```bob@poland:~/src/problems_for_computer_solution/07_armstrong_numbers\$ ./armstrong4macro
armstrong number of 153 is 153
armstrong number of 370 is 370
armstrong number of 371 is 371
armstrong number of 407 is 407
armstrong number of 1634 is 1634
armstrong number of 8208 is 8208
armstrong number of 9474 is 9474
bob@poland:~/src/problems_for_computer_solution/07_armstrong_numbers\$
```