helboy 002
helboy 002

Reputation: 43

Print Armstrong numbers between 1 to 10 million

How to write a logic using for loop or while loop for printing Armstrong numbers?

Someone kindly explain how to print Armstrong numbers between 1 to 1,00,00,000.

This the algorithm that I followed

step 1 : initializing variable min,max,n,sum,r,t
step 2 : my $n = <>;
step 3 : to find base of $n
step 4 : using for loop 
        ( for (n = min; n < max ; n++ )
step 5 : some logic like 
        n=t,sum =0,r=t%10,t=n/10,
step 6 : 
        sum = sum + (n ^ base );
step 6 : 
        if ( sum == num ) print Armstrong numbers else not.

I tried to code this my code look like this

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $n;
chomp($n);

my $min = 1;
my $max = 10000000
my $r;
my $sum;
my $t;

my $base = length($n);
print "base is $base\n";

for ($n = $min; $n <= $max; $n++) {
  $t = $n;
  $sum = 0;
  while ($t != 0) {
    $r = $t % 10;
    $t = $t / 10;
    {
      $sum = $sum + ($base * $r);
    }
    if ($sum == $n) {
      print "$n\n";
    }
  }
}

Upvotes: 0

Views: 1885

Answers (3)

David W.
David W.

Reputation: 107060

Several things:

  • It's bad practice to declare something with my until you need it.
  • You must remember that numbers are also strings, and can be manipulated by string functions like split.
  • C-like loops are discouraged in Perl because they're hard to read.
  • Constants should be ...well... constant.

Here's my attempt. I use split to split up my digits into an array of digits. This is a lot easier than dividing constantly by ten. I can get the number of digits by simply taking the scalar value of my @digits array.

I can then loop through @digits, taking each one to the power of $power and adding it to sum. I use the map command for this loop, but I could have used another for loop too.

#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);

use constant {
    MIN             => 1,
    MAX             => 1_000_000,
};

for my $number ( (+MIN..+MAX) ) {
    my @digits = split //, $number;
    my $power = @digits;
    my $sum = 0;
    map { $sum += $_**$power } @digits;
    if ( $sum == $number ) {
        say "$number is an Armstrong number";
    }
}

And my output:

1 is an Armstrong number
2 is an Armstrong number
3 is an Armstrong number
4 is an Armstrong number
5 is an Armstrong number
6 is an Armstrong number
7 is an Armstrong number
8 is an Armstrong number
9 is an Armstrong number
153 is an Armstrong number
370 is an Armstrong number
371 is an Armstrong number
407 is an Armstrong number
1634 is an Armstrong number
8208 is an Armstrong number
9474 is an Armstrong number
54748 is an Armstrong number
92727 is an Armstrong number
93084 is an Armstrong number
548834 is an Armstrong number

Took a bit over five seconds to run.

Instead of map, I could have done this loop:

for my $digit ( @digits ) {
    $sum = $sum + ( $digit ** $power);
}

Upvotes: 1

user1558455
user1558455

Reputation:

Your code seems to be right, but you have some kind of problems with your start. For example you dont read from STDIN or from @ARGV. Would you do that, you just have a small problem with your calculating of the exponential calculation. In most Programming Languages, the syntax for a exponential calculation is ** or a pow() function. I really dont understand, for what this part is:

while ($t != 0) {
    $r = $t % 10;
    $t = $t / 10;
    {
      $sum = $sum + ($base * $r);
    }
    if ($sum == $n) {
      print "$n\n";
    }
}

For what is the naked block? Why do you use the modulus? .. Well i give you a small code for calculating the armstrong numbers with bases of 1..100, between 0 and 10million:

#!/usr/bin/perl
use strict;
use warnings;
foreach my $base (0..100) {               # use the foreach loop as base
  for my $num (0..10_000_000) {           # and use numbers between this range
    my $ce=0;                             # ce = calculated exp.
    foreach my $num2 (split //,$num ) {   # split each number for calc each
      $ce += $num2 ** $base;              # exp. and adding it (see algorithm)
    }
    if ($num == $ce) {                    # when the exp. num and the number
      print "$base => $num\n";            # itself equals, its a armstrong number
    }                                     # print that
  }
}

Upvotes: 0

Glitch Desire
Glitch Desire

Reputation: 15043

Did this one at university...

I dug out the one I made in C and converted it to perl for you (it may not be the best way to do this, but it is the way I did it):

#!/usr/bin/env perl

use strict;
use warnings;

my $min = 1;
my $max = 10000000;

for (my $number = $min; $number <= $max; $number++) {
    my @digits = split('', $number);
    my $sum = 0;
    foreach my $digit (@digits) {
        $sum += $digit**length($number);
    }
    if ($sum == $number) {
        print "$number\n";
    }
}

(Demo - 1 to 9999 due to execution time limit)

Upvotes: 0

Related Questions