in reply to Anyone use "xor" in conditionals?

It has its uses. The conventional way of determining if a year is leapyear goes something like this code from Date::Leapyear

sub isleap { my ($year) = @_; return 1 if (( $year % 400 ) == 0 ); # 400's are leap return 0 if (( $year % 100 ) == 0 ); # Other centuries are not return 1 if (( $year % 4 ) == 0 ); # All other 4's are leap return 0; # Everything else is not }

This can also be written as

not $year % 4 xor $year % 100 xor $year % 400;

Proof :)

print $_, ((not $_ % 4 xor $_ % 100 xor $_ % 400) ? ' is ' : ' is not ', 'a leap year'), $/ for 1996, 1997, 1998, 1999, 2000, 2004, 2100; 1996 is a leap year 1997 is not a leap year 1998 is not a leap year 1999 is not a leap year 2000 is a leap year 2004 is a leap year 2100 is not a leap year

You should probably also seach for '^', but as I discovered, this is a sight more complex isolate the xor uses from all the other uses perl makes of this character.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


Replies are listed 'Best First'.
Re: Anyone use "xor" in conditionals?
by Abigail-II (Bishop) on Jul 14, 2003 at 07:52 UTC
    Such code irks me. It always has to perform three modulus operations, even while in 99% of the cases it doesn't have to. The Date::Leapyear code irks me too, as it tests the rare cases first. I prefer code like the following:
    sub is_leap { my $year = shift; return 0 if $year % 4; return 1 if $year % 100; !($year % 400) }

    That code does one modulus operation in 75% of the cases, two modules operations in 24% of the cases, and only in 1% of the cases, it does 3 modulus operations.

    A benchmark shows the expected results. The code that always does three modulus operations is the slowest - the code that on averages does the least modulus operations is the fastest.

    #!/usr/bin/perl use strict; use warnings; use Benchmark qw /cmpthese/; sub isleap { my ($year) = @_; return 1 if (( $year % 400 ) == 0 ); # 400's are leap return 0 if (( $year % 100 ) == 0 ); # Other centuries are not return 1 if (( $year % 4 ) == 0 ); # All other 4's are leap return 0; # Everything else is not } sub browseruk { my ($year) = @_; not $year % 4 xor $year % 100 xor $year % 400; } sub abigail { my ($year) = @_; return 0 if $year % 4; return 1 if $year % 100; !($year % 400) } cmpthese -10 => { isleap => 'my $v = isleap $_ for 1800 .. 2199', browseruk => 'my $v = browseruk $_ for 1800 .. 2199', abigail => 'my $v = abigail $_ for 1800 .. 2199', }; __END__ Benchmark: running abigail, browseruk, isleap, each for at least 10 CP +U seconds... abigail: 11 wallclock secs (10.90 usr + 0.00 sys = 10.90 CPU) @ 18 +43.58/s (n=20095) browseruk: 10 wallclock secs (10.48 usr + 0.01 sys = 10.49 CPU) @ 14 +09.82/s (n=14789) isleap: 11 wallclock secs (10.76 usr + 0.01 sys = 10.77 CPU) @ 14 +54.04/s (n=15660) Rate browseruk isleap abigail browseruk 1410/s -- -3% -24% isleap 1454/s 3% -- -21% abigail 1844/s 31% 27% --

    Abigail

      Ah! But if it is out and out speeed we are after then I might have offered :)

      sub buk2 { $_[0] % 4 ? 0 : $_[0] % 100 ? 1 : not $_[0] % 400; } Rate browseruk isleap abigail buk2 browseruk 82.8/s -- -40% -54% -67% isleap 138/s 67% -- -24% -45% abigail 180/s 118% 31% -- -28% buk2 251/s 203% 82% 39% --

      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


        And why haven't you offered this as a patch to Date::Leapyear or any of the other Date:: modules? Hmmm?!? Or, even better, offer both the pureperl and XS versions ...

        In other words, it's through these incremental improvements that modules are made as strong as they can be. That kind of code is exactly the code that belongs in modules. They're supposed to fast, commented, and full of black magic. That's why modules exist!

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        I wasn't looking for the fastest solution to this particular problem. My 'solution' looked similar to the one from the Date module on purpose. I wanted to show the effect of changing the order, so I used the same style which would make it more obvious what the effect is.

        Nested ?: is of course faster than repeated statement modifiers.

        Abigail

        PS: Could you fix your sig? It doesn't seem to close its font element - replying in a textform with fontsize = 1 is very annoying.

Re: Re: Anyone use "xor" in conditionals?
by bsb (Priest) on Jul 14, 2003 at 23:32 UTC
    Well, it helped me:
    $ perl -MO=Deparse,-p -e 'not $year % 4 xor $year % 100 xor $year % 40 +0;' (((not ($year % 4)) xor ($year % 100)) xor ($year % 400));