Re: Product of a list of numbers?
by Zaxo (Archbishop) on Jan 23, 2004 at 03:09 UTC
|
Your way is fine, but if you need more speed, look at PDL,
sub product {
pdl( shift )->prodover;
}
In the interest of speed, you'd probably want to work with piddles from the start, rather than converting like that.
| [reply] [d/l] |
|
Now the most idiomatic approach would be:
PDL->topdl(shift)->prodover
as topdl will not duplicate the data if it is already a pdl/ndarray. | [reply] [d/l] [select] |
Re: Product of a list of numbers?
by BrowserUk (Patriarch) on Jan 23, 2004 at 02:51 UTC
|
Can't say if its more efficient, but you could use List::Util::reduce.
use List::Util 'reduce';
my @a = ( 1, 2, 3, 4, 5 );
print reduce{ $a * $b } @a;
120
| [reply] [d/l] |
|
#!/usr/bin/env perl
use strict;
use warnings;
use List::Util 1.35 'product';
my @a = (1, 2, 3, 4, 5);
print product @a;
| [reply] [d/l] |
Re: Product of a list of numbers?
by PodMaster (Abbot) on Jan 23, 2004 at 01:12 UTC
|
FYI, for future searches, you can safely omit "perl" from "perl product" (what's next, "perl array" ? :)).
However, with the loop and all, it seems like a terribly inefficient method of doing such a thing. Anyone have a smarter way?
Why does it seem inefficient? It's the most straight forward way to accomplish the task.
Maybe not as "elegant" (matter of opinion) as
sub product {
my $list = shift;
my $prod = 1;
$prod *= $_ for @$list;
return $prod;
}
but it's pretty much as efficient as it gets.
MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!" | I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README). | ** The third rule of perl club is a statement of fact: pod is sexy. |
| [reply] [d/l] |
Re: Product of a list of numbers?
by Roger (Parson) on Jan 23, 2004 at 01:11 UTC
|
I think your method is quite efficient already in purl Perl. If you are looking for ways to speed up, you should have a look at Inline::C or perlxs.
| [reply] |
Re: Product of a list of numbers?
by Popcorn Dave (Abbot) on Jan 23, 2004 at 05:59 UTC
|
Just out of curiosity, is there a speed issue when using map or would it really depend on the size of the array being mapped over?
Given:
use strict;
my @list = (1,2,3,4,5);
my $result = 1;
map {$result *= $_} @list;
print $result;
I realize that TIMTOWTDI, but is this a good place to use map, is the loop preferable, or are they about the same?
There is no emoticon for what I'm feeling now.
| [reply] [d/l] |
|
Why don't you Benchmark it?
Updated: Added my own Benchmark result.
use strict;
use Benchmark qw/ cmpthese timethese /;
use List::Util qw/ reduce /;
my @list = 1..10;
cmpthese(
timethese(1000000, {
'map_void' => '&map_void',
'for_loop' => '&for_loop',
'list_reduce' => '&list_reduce',
}));
# printf "%d, %d, %d\n", map_void(), for_loop(), list_reduce();
sub map_void {
my $result = 1;
map {$result *= $_} @list;
return $result;
}
sub for_loop {
my $result = 1;
$result *= $_ foreach @list;
return $result;
}
sub list_reduce {
return reduce { $a * $b } @list;
}
__END__
Benchmark: timing 1000000 iterations of for_loop, list_reduce, map_voi
+d...
for_loop: 4 wallclock secs ( 5.43 usr + 0.00 sys = 5.43 CPU) @ 18
+4229.92/s
(n=1000000)
list_reduce: 9 wallclock secs ( 8.46 usr + 0.00 sys = 8.46 CPU) @ 1
+18175.37/s
(n=1000000)
map_void: 5 wallclock secs ( 4.52 usr + 0.00 sys = 4.52 CPU) @ 22
+1385.88/s
(n=1000000)
Rate list_reduce for_loop map_void
list_reduce 118175/s -- -36% -47%
for_loop 184230/s 56% -- -17%
map_void 221386/s 87% 20% --
| [reply] [d/l] |
|
use strict;
use warnings;
use Benchmark;
my @list = ( 1 .. 500 );
my $count = 25000;
timethese ( $count, {
'Map' => sub { my $result = 1; map { $result *= $_ } @list; },
'For' => sub { my $result = 1; $result *= $_ for @list; }
} );
__OUTPUT__
Benchmark: timing 25000 iterations of For, Map...
For: 11 wallclock secs (10.62 usr + 0.00 sys = 10.62 CPU) @ 2355.16/s
+ (n=25000)
Map: 11 wallclock secs (11.18 usr + 0.00 sys = 11.18 CPU) @ 2236.94/s
+ (n=25000)
The moral... There's no way to perform a mathematical operation based on the value of each element of a list of arbitrary values, without looking at each element of the list. And that implies (and requires) some from of iteration. map and for seem to be pretty close to each other in terms of efficiency in iterating over the list.
On the other hand, if the list consists of a known sequence, it is possible to break out the math-fu to derive a non-iterative solution. Brute force is necessary in the absence of a known mathematical sequence though.
| [reply] [d/l] [select] |
|
I'm quite surprised by your results. It shows the reduce
version to be the slowests, and it suggests that using a
map with a block is faster than a for statement modifier.
The former needs to enter/leave a block for each iteration,
and the latter doesn't. A benchmark on my box shows different
results:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw /cmpthese timethese/;
use List::Util qw /reduce/;
our @list = 1 .. 50;
our ($map_b, $map_e, $for_m, $for_b, $red, $bc, $eval);
print "Perl version: $].\n";
system "cat /proc/version";
cmpthese -10 => {
map_block => '$::map_b = 1; map {$::map_b *= $_} @::list',
map_expr => '$::map_e = 1; map $::map_e *= $_, @::list',
for_mod => '$::for_m = 1; $::for_m *= $_ for @::list',
for_block => '$::for_b = 1; foreach (@::list) {$::for_b *= $_}',
reduce => '$::red = reduce {$a * $b} @::list',
bc => q !local $" = "*";
$::bc = `echo '@::list' | bc`!,
eval => '$::eval = eval join "*" => @::list',
};
print "Map block: $map_b\n";
print "Map expres: $map_e\n";
print "For modifier: $for_m\n";
print "For block: $for_b\n";
print "Reduce: $red\n";
print "bc: $bc\n";
print "Eval: $eval\n";
__END__
Perl version: 5.008003.
Linux version 2.4.18-3 (bhcompile@daffy.perf.redhat.com) (gcc version
+2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #1 Thu Apr 18 07:37:53 ED
+T 2002
Rate bc eval map_block for_block map_expr for_m
+od reduce
bc 2779/s -- -55% -88% -94% -95% -9
+5% -95%
eval 6199/s 123% -- -73% -87% -88% -8
+8% -89%
map_block 22904/s 724% 269% -- -53% -55% -5
+7% -60%
for_block 49041/s 1664% 691% 114% -- -3% -
+9% -13%
map_expr 50669/s 1723% 717% 121% 3% -- -
+6% -11%
for_mod 53638/s 1830% 765% 134% 9% 6%
+-- -5%
reduce 56651/s 1938% 814% 147% 16% 12%
+6% --
Map block: 3.0414093201713378e+64
Map expres: 3.0414093201713378e+64
For modifier: 3.0414093201713378e+64
For block: 3.0414093201713378e+64
Reduce: 3.0414093201713378e+64
bc: 30414093201713378043612608166064768844377641568960512000
+000000000
Eval: 3.0414093201713378e+64
Abigail | [reply] [d/l] |
Re: Product of a list of numbers?
by Skeeve (Parson) on Jan 23, 2004 at 10:14 UTC
|
Benchmark on your own, but I'd give this a try:
sub product {
return eval join '*',@_;
}
| [reply] [d/l] |
Re: Product of a list of numbers?
by Abigail-II (Bishop) on Jan 23, 2004 at 10:20 UTC
|
For a quick and dirty way, I like to do stuff like:
sub product {
my $list = shift;
local $" = "*";
`echo '@$list' | bc`
}
Abigail | [reply] [d/l] |
Language::Functional
by sleepingsquirrel (Chaplain) on Jan 23, 2004 at 18:38 UTC
|
Maybe not 100% on-topic, but you might look into Language::Functional which has a lot of interesging array processing subroutines taken from the realm of functional programming. (and yes, there is one for finding the product). | [reply] |