good chemistry is complicated,and a little bit messy -LW PerlMonks

Sheer idle curiousity . . .

by TheMonkWithoutVows (Novice)
 on Oct 23, 2013 at 21:32 UTC Need Help??
TheMonkWithoutVows has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

I have a very simple bit of code where I basically want to set a var \$wait value to 0 if it is a negative number and stay as is if not. This resulted in a debate with a work colleague as to which of the following lines would be faster.

so we tested . . .

```use Benchmark qw( cmpthese ) ;

my \$wait = -34;

cmpthese( -2, {
a=>sub{
\$wait = \$wait  < 0 ? 0 : \$wait ;
\$wait = -34;
},
b=>sub{
if (\$wait < 0 ){ \$wait = 0};
\$wait = -34;
},

c=>sub{
\$wait = 0 unless \$wait > 0;
\$wait = -34;
},

d=>sub{
\$wait = 0 unless abs(\$wait);
\$wait = -34;
},

and we were amazed by the results . . .. with a negative number:

```       Rate    a    b    c    d
a 4216652/s   -- -16% -17% -36%
b 5010637/s  19%   --  -2% -24%
c 5094673/s  21%   2%   -- -23%
d 6616606/s  57%  32%  30%   --

with a positive number:

```      Rate    a    b    c    d
a 3542992/s   --  -5%  -6% -50%
b 3742730/s   6%   --  -1% -47%
c 3766874/s   6%   1%   -- -47%
d 7084993/s 100%  89%  88%   --

Two questions -

• why would using abs be so much faster - (intuitively I felt using a function would add to the cost)?
• has anyone got a faster way?

Replies are listed 'Best First'.
Re: Sheer idle curiousity . . .
by BrowserUk (Pope) on Oct 23, 2013 at 22:14 UTC
why would using abs be so much faster

Because it requires less opcodes.

• With the ternary, it has to:
3. perform the compare;
4. perform an assignment in both branches.
• With the unless \$x >= 0 (your condition is wrong), it has to
3. perform the compare;
4. perform an assignment in one branch.
• With the unless abs \$x the is no constant to load; and abs is just an opcode the same as greater than or less than:
2. perform the compare;
3. perform an assignment in one branch.

Best shown by the difference in the Concise output, where each successively faster option requires one less opcode than the precedent:

```C:\test>perl -MO=Concise -E"my\$x=-1; \$x = \$x<0?0:\$x;"
e  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 46 -e:1) v:%,{ ->3
5     <2> sassign vKS/2 ->6
3        <\$> const[IV -1] s ->4
6     <;> nextstate(main 47 -e:1) v:%,{ ->7
d     <2> sassign vKS/2 ->e
-        <1> null sK/1 ->c
a           <|> cond_expr(other->b) sK/1 ->f
9              <2> lt sK/2 ->a
8                 <\$> const[IV 0] s ->9
b              <\$> const[IV 0] s ->c
-e syntax OK

C:\test>perl -MO=Concise -E"my\$x=-1; \$x = 0 unless \$x >=0;"
e  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 46 -e:1) v:%,{ ->3
5     <2> sassign vKS/2 ->6
3        <\$> const[IV -1] s ->4
6     <;> nextstate(main 47 -e:1) v:%,{ ->7
-     <1> null vK/1 ->e
a        <|> or(other->b) vK/1 ->e
9           <2> ge sK/2 ->a
8              <\$> const[IV 0] s ->9
d           <2> sassign vKS/2 ->e
b              <\$> const[IV 0] s ->c
-e syntax OK

C:\test>perl -MO=Concise -E"my\$x=-1; \$x = 0 unless abs(\$x);"
d  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 46 -e:1) v:%,{ ->3
5     <2> sassign vKS/2 ->6
3        <\$> const[IV -1] s ->4
6     <;> nextstate(main 47 -e:1) v:%,{ ->7
-     <1> null vK/1 ->d
9        <|> or(other->a) vK/1 ->d
8           <1> abs[t3] sK/1 ->9
c           <2> sassign vKS/2 ->d
a              <\$> const[IV 0] s ->b
-e syntax OK

Of course, speed is no good to you if it doesn't perform the required function ... (davido++)

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Thanks that really is clear - appreciated.
Re: Sheer idle curiousity . . .
by davido (Archbishop) on Oct 23, 2013 at 21:45 UTC

What does your intuition tell you this code does?

```d=>sub{
\$wait = 0 unless abs(\$wait);
\$wait = -34;
},

In particular, abs returns the absolute value. The absolute value of -34 is 34, which is "true". Since your condition is never false, you never fall through to the action of the "unless" clause.

Dave

My intuition tells me it's been a long day and typos are creeping in :-)

The last test should have read:

```   d=>sub{
\$wait = 0 unless (\$wait == abs(\$wait));
\$wait = -34;
},
I thought the results had shot up on my home pc.
```      Rate    d    c    b    a
d 3468819/s   --  -8% -10% -13%
c 3780923/s   9%   --  -1%  -5%
b 3834916/s  11%   1%   --  -4%
a 3997317/s  15%   6%   4%   --

and

Rate    d    c    b    a
d 3246175/s   --  -8% -15% -17%
c 3526456/s   9%   --  -7%  -9%
b 3799184/s  17%   8%   --  -2%
a 3890565/s  20%  10%   2%   --

It's still the outright winner - so the questions still stand.

Besides what David just said, it seems to me that the operation of simply setting a sign bit and then testing for 0 would inherently faster than any of the other comparisons if the resulting code is optimized. I know that would be the case if I were coding that in assembly.

The answer to the question "Can we do this?" is always an emphatic "Yes!" Just give me enough time and money.
if the resulting code is optimized.

Its not. It just results in less opcodes.

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Sheer idle curiousity . . .
by Anonymous Monk on Oct 24, 2013 at 02:48 UTC

This may be faster:

```    e=>sub{
\$wait *= \$wait > 0;
\$wait = -34;
},

For negative numbers:

```        Rate    d    b    a    c    e
d  7216838/s   --  -7% -13% -16% -35%
b  7785170/s   8%   --  -6% -10% -30%
a  8270205/s  15%   6%   --  -4% -26%
c  8609980/s  19%  11%   4%   -- -23%
e 11128061/s  54%  43%  35%  29%   --

For positive numbers:

```        Rate    a    d    e    c    b
a  9665991/s   -- -10% -14% -24% -26%
d 10777285/s  11%   --  -4% -15% -17%
e 11190507/s  16%   4%   -- -12% -14%
c 12748698/s  32%  18%  14%   --  -2%
b 13022958/s  35%  21%  16%   2%   --

Now that is just dandy

%wait *= \$wait < 0

. . . . is the clear winner

Take a bow Anonymous Monk

Re: Sheer idle curiousity . . .
by vsespb (Chaplain) on Oct 23, 2013 at 23:01 UTC
As @TheMonkWithoutVows pointed out in Re^2: Sheer idle curiousity . . ., the code
```\$wait = 0 unless abs(\$wait);
unlike other examples, never assigns anything to \$wait if \$wait is -34.

Proof:
```my \$wait = -34;
\$wait = 0 unless abs(\$wait);
print \$wait;
prints -34

So if you change your benchmark to
```\$wait = 0 if abs(\$wait);
you'll see, difference is small (I got 4%). (even through abs() is still used).

UPD:Oh, @TheMonkWithoutVows and you(OP) are same persons :)
Re: Sheer idle curiousity . . .
by hdb (Monsignor) on Oct 24, 2013 at 07:27 UTC

Running a comparison of a, c and e several times on Win 7, Strawberry 5.16 shows the following results:

```       Rate   e   a   c
e 7079226/s  -- -1% -3%
a 7185758/s  2%  -- -1%
c 7269278/s  3%  1%  --

Rate   e   c   a
e 7072032/s  -- -1% -3%
c 7143388/s  1%  -- -2%
a 7316126/s  3%  2%  --

Rate   c   e   a
c 7161561/s  -- -1% -4%
e 7257544/s  1%  -- -2%
a 7427981/s  4%  2%  --

so my conclusion would be that the difference between the three is negligible. This is with -34 as the test number. For +34 the picture is quite different:

```        Rate    e    a    c
e  6807195/s   -- -26% -37%
a  9201425/s  35%   -- -15%
c 10867659/s  60%  18%   --

where c is a clear and consistent winner.

What shall I make of this in the light of the thread above?

What shall I make of this in the light of the thread above?

That CPUs have differences in performance, and so do Perl versions?

```# This is perl, v5.10.1 (*) built for i486-linux-gnu-thread-multi

# negative
Rate    d    c    e    a    b
d 1219274/s   --  -7% -15% -20% -31%
c 1315339/s   8%   --  -9% -13% -26%
e 1441482/s  18%  10%   --  -5% -19%
a 1519028/s  25%  15%   5%   -- -15%
b 1778883/s  46%  35%  23%  17%   --

# positive
Rate    d    e    c    a    b
d 1300194/s   --  -3%  -6% -13% -13%
e 1336169/s   3%   --  -3% -10% -10%
c 1375954/s   6%   3%   --  -7%  -8%
a 1486080/s  14%  11%   8%   --  -0%
b 1492276/s  15%  12%   8%   0%   --

The winner here is, quite unexpectedly, B.

Another cpu, also on Perl 5.10.1 but amd64, says B is 80% faster than the worst contender (E) when negative; and A is 51% faster than E (B having the second place at 42% faster) when positive.

Third cpu with Perl 5.14.4 gives a negligible win for E -- D being the low anchor. So I think we can conclude that the Perl version matters the most?

Re: Sheer idle curiousity . . .
by AnomalousMonk (Chancellor) on Oct 24, 2013 at 03:50 UTC

And you and your cow-orkers spent how much time on this today?!? I wish I worked where you work. (Actually, I foresee there may be a couple of openings RSN...:)

It's called "professional development time" at the end of the sprint where I work. :)

The answer to the question "Can we do this?" is always an emphatic "Yes!" Just give me enough time and money.
I work at The Unemployment Line. You don't want to work here. There are plenty of openings.
Re: Sheer idle curiousity . . .
by ikegami (Pope) on Oct 25, 2013 at 14:50 UTC

To put it into perspective, the slowest one of the above takes 180 billionths of a second, while a subroutine call with a single ten-character string argument takes 650 billionths of a second.

If your tenth of millionths of seconds are that precious, you should probably inline your subs.

```'\$wait = 0 unless (\$wait == abs(\$wait)); \$wait = 34;'
'sub { my (\$x) = @_; }->(q{abcdefghij})'

Create A New User
Node Status?
node history
Node Type: perlquestion [id://1059354]
Approved by keszler
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (2)
As of 2018-04-22 03:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My travels bear the most uncanny semblance to ...

Results (82 votes). Check out past polls.

Notices?