Re: Anyone use "xor" in conditionals?
by Abigail-II (Bishop) on Jul 14, 2003 at 00:48 UTC
|
Yes it is. Because it's awkward to write:
if ((COND1 || COND2) && !(COND1 && COND2))
specially when either condition is either expensive,
or has side-effects.
A while ago, I was writing a small script that recursively
compared directories (and no, plain diff didn't do, although
the script called diff repeatedly). Since I was interested
in the similarities instead of the differences, at one moment
I wrote:
next if -d $dir1 xor -d $dir2
If either of the arguments wasn't a directory, but the
other was, they couldn't match. But if both were, or both
weren't, furthermore analysis was necessary.
And yes, I know, xor can be written using other
primitives as well. But that's not an argument, unless you
also think 'for', 'while' and other looping constructs
are redundant, because we have 'goto'.
Abigail | [reply] [d/l] [select] |
|
Atually there's an easier way to write xor:
if ( (COND1 and not COND2) or ((not COND1) and COND2) )
This way the conditions are evaluated less times (I think this is the easier way of expressing 'xor' in terms of 'and', 'or' and 'not')
While I agree that xor is a useful operation, there aren't that many places where it applies, as many situations rule themselves out in an or comparison.
For example, unless you are trying to model the rainbow, if ( $raining or $sunny ) contemplates the whole weather (simplified) model. Admitedly, in some cases the possibility arises: just use it. But as CPAN demonstrates, there aren't so many examples.
Now, if you are implementing a parser, or any complicated enough state machine...
Best regards,
-- our $Perl6 is Fantastic;
| [reply] [d/l] [select] |
|
I use xor at a few places in the Regexp::Common
test suite. I've two variables, one saying whether a
regexp matched, and another saying whether the regexp
should have matched. The test fails if one variable is
true, the other false. Hence, an xor.
Abigail
| [reply] |
|
|
This way the conditions are evaluated less times
Eh? Not so.
$ perl -le 'print "T" if (print "foo" xor print "bar")'
foo
bar
$ perl -le 'print "T" if ((print "foo" and not print "bar") or (not pr
+int "foo" and print "bar"))'
foo
bar
foo
At best, the expanded version will result in the same number of evaluations.
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] |
|
|
Can you say that the internals of perl don't do the optimizations on user behalf? I'd hope that perl automatically thows out the expression w/o doing it fully if it finds out it's dead in the middle.
btw, your way is for those who don't have the concept, or truth table, memorized and reproduce it w/o thinking. Nothing wrong w/ it though.
Regardless, xor isn't something that is as easily applicapble such as, the plus operator or just the and operator.
Certain tools, for certain situations.
| [reply] |
|
|
Wouldn't that (next if -d $dir1 xor -d $dir2) be exactly the same as next if -d $dir1 == -d $dir2 ? Why would you choose xor over that?
| [reply] [d/l] [select] |
|
Because I have warnings turned on.
Abigail
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in.
|
Re: Anyone use "xor" in conditionals?
by BrowserUk (Patriarch) on Jul 14, 2003 at 02:06 UTC
|
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 :)
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
| [reply] [d/l] [select] |
|
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 | [reply] [d/l] [select] |
|
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
| [reply] [d/l] |
|
|
|
|
|
|
$ perl -MO=Deparse,-p -e 'not $year % 4 xor $year % 100 xor $year % 40
+0;'
(((not ($year % 4)) xor ($year % 100)) xor ($year % 400));
| [reply] [d/l] |
Re: Anyone use "xor" in conditionals?
by tachyon (Chancellor) on Jul 14, 2003 at 06:07 UTC
|
It is one way to write a flip_flop, like in this snippet which uses a xor flip flop to alternate row colours in a 'pretty' HTML table...
sub pretty_table {
my ($ary, $width, $no_center) = @_;
my $header = shift @$ary;
$width = $width ? qq!width="$width"! : '';
my $html = qq!<table border="0" cellpadding="2" cellspacing="1" $w
+idth>\n!;
my $cols = scalar @$header;
$html .= get_row( $header, $cols, 'header' );
my $flip_flop = 1;
for my $row_ref ( @$ary ) {
my $class = $flip_flop ? 'light' : 'dark';
$html .= get_row( $row_ref, $cols, $class );
$flip_flop ^= 1;
}
$html .= qq! <tr>\n <td colspan="$cols" class="header">
+</td>\n </tr>\n!;
$html .= "</table>\n";
$html = qq!<div align="center">\n<center>\n$html\n</center>\n</div
+>! unless $no_center;
return $html
}
sub get_row {
my ( $row_ref, $cols, $class ) = @_;
my $html = qq! <tr>\n!;
for my $td ( 0.. $cols-1 ) {
my $data = $row_ref->[$td] || ' ';
$html .= qq! <td class="$class">$data</td>\n!;
}
$html .= " </tr>\n";
return $html;
}
Of course you can get the same effect using $flip++ % 2 == 0 amongst others.
cheers
tachyon
s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print
| [reply] [d/l] [select] |
|
Hehe, whenever I use flipflops I confuse the cow orkers. However, I've always written it differently:
my $flipflop = 1;
for my $row_ref ( @$ary ) {
...
$flip_flop = 1 - $flipflop;
}
I'm not sure that this is potentially more efficient in Perl (probably less efficent?), but is an idiom I remember from my Amiga asm days. Personally, I also think it's easier to see what's going on too :) | [reply] [d/l] |
|
I'm a bit confused by these flipflops being used, as well as the ternary thing, to alternate colours.
I long ago whittled it down to just
$bgcolor = ($bgcolor eq 'white'?'black':'white');
which flips itself.
Every bit of code is either naturally related to the problem at hand, or else it's an accidental side effect of the fact that you happened to solve the problem using a digital computer.
M-J D | [reply] [d/l] |
|
|
|
I prefer a data driven approach.
my @cycle = ('#fff', '#fff', '#fff', '#ccc', '#ccc');
my $i = 0;
# ...
$foo .= $cycle[$i++ % @cycle];
# ...
That way it is a no-brainer to use any pattern you wish. "Capture similarities in code, disparities in data."
Makeshifts last the longest. | [reply] [d/l] |
Re: Anyone use "xor" in conditionals? (yes/no)
by tye (Sage) on Jul 14, 2003 at 06:08 UTC
|
if( !$a == !$b ) {
#or
if( !$x != !$y ) {
and those could now be rewritten:
if( not $a xor $b ) {
#or
if( $x xor $y ) {
but I don't adopt new Perl features lightly and I haven't written Perl code that wanted that sort of test since I noticed the existance of xor so I've never used xor, just written code where I would have used it had it been available enough at the time.
Though, I actually find the concept of "these two logical expressions are equal" to be more useful/natural than a logical "xor" (not equal) so I'm more likely to want
if( !$a == !$b ) {
than the other case and I'd probably leave that as-is rather than change it to
if( not $a xor $b ) {
because I find the latter harder to understand. So I'd probably rather have an eqv (pronounced "equivalent") over an xor. (:
- tye | [reply] [d/l] [select] |
|
On at least two occasions (but not very many more than that) I've written code like:
Heh. In my test code I use the syntax you've shown quite regularly. I was unaware that xor did the right thing with undef and hence have used the !$x == !$y or !$x != !$y syntax fairly often.
And I also agree with you that I prefer this syntax to xor as it to me makes the intent of the test easier to see.
---
demerphq
<Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
| [reply] [d/l] [select] |
Re: Anyone use "xor" in conditionals?
by edan (Curate) on Jul 14, 2003 at 07:12 UTC
|
Not that I have anything really earth-shattering to add to what others have written, but just wanted to add another voice to the 'xor can be useful' crowd...
I used xor in the following situation:
There are 3 states, call them A, B, and Z, where the first 2 are sort of similar, and the last is different. I needed a conditional to test for the transition between (A or B) and Z (or vice versa). So instead of writing some monstrous thing like:
if ((($before eq 'A' || $before eq 'B') && $after eq 'Z')
|| ($before eq 'Z' && ($after eq 'A' || $after eq 'B')))
{
# change from A|B <=> Z
}
I simply wrote this:
if ($before eq 'Z' xor $after eq 'Z')
{
# change from A|B <=> Z
}
I hope my explanation made sense... but that's my story of how I used xor...
Update: Upon further reflection, my non-xor conditional would be more simply and accurately written as one of these:
if (($before ne 'Z' && $after eq 'Z')
|| ($before eq 'Z' && $after ne 'Z'))
{
# change from A|B <=> Z
}
if (($before eq 'Z' || $after eq 'Z')
&& !($before eq 'Z' && $after eq 'Z'))
{
# change from A|B <=> Z
}
... and that is equivalent to Abigail-II's summary of xor's logical equivalency: if ((COND1 || COND2) && !(COND1 && COND2))
But I think it's still clear why xor is useful here, and perhaps I shed some light on a real-world usage... Not having looked at the source, but only bsb's post, I am guessing it's similar to the situation here:
/usr/local/lib/perl/5.6.1/DateTime.pm: if ( $self->{tz}->is_floatin
+g xor $was_floating )
-- 3dan | [reply] [d/l] [select] |