vr has asked for the wisdom of the Perl Monks concerning the following question:
use strict; use warnings; use Benchmark 'cmpthese'; my @a = map log, 1..1e6; cmpthese( -2, { 1 => sub {[ map $_ * 4, @a ]}, 2 => sub {[ map $_ / (1/4), @a ]}, }); __END__ Rate 1 2 1 7.70/s -- -27% 2 10.6/s 38% --
Fooling around with integers and floats (inspired by this question: Clean log_10 ?), I found (again!) unknown to me Perl behaviour, which can actually lead to performance issues. Maybe it's open secret and was described 20 years ago. Couldn't come up with good Google query, found nothing, hence this question/observation.
It looks like if scalar contains NV, and though it never has been IV, and another operand is IV, and operator is e.g. multiplication (and some other operators, but not, important, division), then Perl checks if this scalar can be promoted (or is it "demoted"?) to IV, and if so, then result will be IV.
>perl -MDevel::Peek -E "$x=2/1; Dump$x; $y=$x*2; Dump$x; Dump$y" SV = NV(0xd75628) at 0xd75640 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 2 SV = PVNV(0xe26078) at 0xd75640 REFCNT = 1 FLAGS = (IOK,NOK,pIOK,pNOK) IV = 2 NV = 2 PV = 0 SV = IV(0xd75a80) at 0xd75a90 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 4
Though it means some amount of extra work, it could be argued that Perl tries to do "a right thing". However, with arrays, this helpful (?) optimization becomes an anti-DWIM, I think. If array contains just a single element which "looks like integer" (log 1, above), then "optimization" is attempted for all elements. Try range 2..1e6, then there's no penalty. I understand, that (a) as it's said somewhere in FAQ, Perl is not well suited for number crunching, and (b), if properly profiled, difference between multiplication and division by reciprocal somewhere in real program will probably be tiny. Fun fact, nevertheless.
|
|---|