Andrew_Levenson has asked for the wisdom of the Perl Monks concerning the following question:
This script is supposed to find the four 3 digit numbers whose digits, when cubed and added together, equal the original number.
Can anyone check this out and see why it won't work?
use strict;
use warnings;
my $i;
my $j;
my @num;
my @numbers;
for $i(100..999){
undef(@num);
@num=split(//, $i);
foreach $j(@num){
$j**3;
}
if(sum(@num)==$i){
push @numbers, $i;
}
}
print @numbers;
Thanks in advance.
Re: Cube/digit script.
by japhy (Canon) on Mar 10, 2006 at 13:42 UTC
|
You have warnings on! Why don't you read the warning you get? Useless use of exponentiation (**) in void context means that your $j**3 line isn't doing anything with its return value. Perhaps you meant $j **= 3 which would set $j to itself cubed.
I assume you have a sum() function defined somewhere. And your variable scoping leaves something to be desired -- specifically, proper variable scoping. Rewriting only the scoping of your program, I'd do:
my @numbers;
for my $i (100 .. 999) {
my @num = split(//, $i);
foreach my $j (@num) {
$j **= 3;
}
if (sum(@num) == $i) {
push @numbers, $i;
}
}
I have another comment. Why did you use 'for' in one loop and 'foreach' in another? They're not different things, and you're not using the C-style loop, so there's no reason one of them should have a different name from the other.
All in all, I would rewrite this program to use far fewer temporary variables:
my @numbers = grep { sum(map { $_ ** 3 } split //) == $_ } 100 .. 999;
That might be a bit too succinct for you, but it does the same thing as yours.
| [reply] [d/l] [select] |
Re: Cube/digit script.
by wfsp (Abbot) on Mar 10, 2006 at 14:02 UTC
|
153
370
371
407
Here's my take on it :-)
Do you have a sub called sum? I've taken the liberty of assuming you may not.
I've also taken on board japhy's point about scoping and the for loop.
You're not storing the cubes anywhere so I've added a var to hold it.
There is, however, a slight snag. It only finds three!
666
870
960
With the code straigtened out a bit perhaps you can identify the error?
#!/bin/perl5
use strict;
use warnings;
my @numbers;
for my $i (100..999){
my @num = split(//, $i);
my $cubed;
for my $j (@num){
$cubed += $j**3;
}
#my $added;
#$added += $_ for @num;
#print "$i -> $cubed -> $added\n";
if(
($cubed) == $i
){
push @numbers, $i;
}
}
print "$_\n" for @numbers;
Hope this helps | [reply] [d/l] [select] |
|
Ooh, not only does it only find 3, but the three it finds are wrong. O_O There must be an error in my math, i'll have to check that out.
| [reply] |
|
Here, I figured out what was wrong. The $added variable was unnecessary:
use strict;
use warnings;
my $i;
my $j;
my $cubed;
my @num;
my @numbers;
for $i(100..999){
undef($cubed);
undef(@num);
@num=split(//, $i);
for $j(@num){
$cubed+=$j**3;
}
if($cubed==$i){
push @numbers, $i;
}
}
print "$_\n" for @numbers;
Thanks for the help!
| [reply] [d/l] |
Re: Cube/digit script.
by Limbic~Region (Chancellor) on Mar 10, 2006 at 14:18 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use List::Util 'sum';
for (100 .. 999) {
print "$_\n" if sum(map {$_ ** 3} split //) == $_;
}
Grrrr - after I posted I finished reading japhy's post where he provided an even more succinct solution.
| [reply] [d/l] |
|
To me, this one looks more succinct, if a bit too much on one line ;-) But, to take this a bit further, I look at postfix "if" as "grep" ...
print map {
"$_\n"
} grep {
$_ == sum map { $_ ** 3 } split //
} 100 .. 999
IMO, both better (more whitespace) and worse (hiding the loops, removal of parenthesis for the sum function). ;-) (I'm sure others have their own opinions of how they compare.)
Just to make it a bit worse ...
print "$_\n" for grep {
$_ == sum map $_ ** 3, split //
} 100 .. 999
Or is that better? Hmmm... | [reply] [d/l] [select] |
Re: Cube/digit script.
by perlsen (Chaplain) on Mar 10, 2006 at 14:23 UTC
|
Hi Andrew,
I have rewritten your script(same as yours),
I am not sure whether my output is correct or not,
I just tried to get the output Result, What you are trying now
I hope this might help
use strict;
use warnings;
my ($i,$j,$l,$s);
my (@num,@numbers);
for $i(100..999)
{
undef(@num);
@num=split(//, $i);
foreach $j(@num){ $j=$j**3;}
$s=0;
for $l(@num) {$s = $s + $l;}
if( $s == "$i") {push (@numbers, $i);}
}
print @numbers;
#output is
153370371407
Thanks,
perlsen
UPDATE: This script was written by me to produce the output for your program only. I am not clearly go through your script. Any way, This is waste of my precious time. and Thanks for some fellow monks good response.
| [reply] [d/l] |
Re: Cube/digit script.
by Yzzyx (Beadle) on Mar 10, 2006 at 14:28 UTC
|
#!/usr/bin/perl
use warnings;
for my $a ( 1 .. 9 ) {
for my $b ( 0 .. 9 ) {
for my $c ( 0 .. 9 ) {
my $num = $a.$b.$c;
my $sum = ( $a ** 3 ) + ( $b ** 3 ) + ( $c ** 3 );
print "$num\n" if $num == $sum;
}
}
}
| [reply] [d/l] |
|
A minor quibble: I would avoid using $a and $b in this context, since they are global sort variables -- it has the potential to confuse a casual reader of your code. How 'bout $c, $d and $e instead? :)
No good deed goes unpunished. -- (attributed to) Oscar Wilde
| [reply] |
|
|