Ellhar has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks, I’ve done some perl in the past (wish I’d seen this site then) but it has been a while. I have some if logic/parentheses not working. The code is meant to identify outliers in triplicate data values. Here is some of it.
$a= 20; $b= 22.5; $c= 23 $atob = $a - $b; $btoc = $b - $c; $atoc = $a - $c; if (((atob > 1 ) || (atob < -1)) && ((atoc > 1) || (atoc < -1)) && ((b +toc > 1) || (btoc < -1))) { print OUTFILE "DIFF > 1 all three\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 1; $matrixflags[$row - 2][$i] = 1; } elsif (((atob > 1) || (atob < -1)) && ((btoc < 1) && (btoc > -1)) && ( +(atoc > 1) || (atoc < -1))) { print OUTFILE "DIFFA > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 0; $matrixflags[$row - 2][$i] = 0; } elsif (((atob > 1) || (atob < -1)) && ((btoc > 1) || (btoc < -1)) && ( +(atoc < 1) && (atoc > -1))) { print OUTFILE "DIFFB > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 0; $matrixflags[$row - 3][$i] = 1; $matrixflags[$row - 2][$i] = 0; } elsif (((atob < 1) && (atob > -1)) && ((btoc > 1) || (btoc < -1)) && ( +(atoc > 1) || (atoc < -1))) { print OUTFILE "DIFFC > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 0; $matrixflags[$row - 3][$i] = 0; $matrixflags[$row - 2][$i] = 1; } #So in this example in my head the 1st elsif should be executed. #Difference $atob = 1.5 so ((atob > 1) || (atob < -1)) is true. #Difference $btoc = 0.5 so ((btoc < 1) && (btoc > -1)) is true. #Difference $atoc = 3 so ((atoc > 1) || (atoc < -1)) is true.
During debugging the values seem to make sense but I’m not executing the any of the statements. Any ideas? Thanks Elliott

Replies are listed 'Best First'.
Re: if logic OR parentheses problem
by FunkyMonk (Bishop) on Oct 26, 2007 at 14:12 UTC
    Try adding
    use strict; use warnings;

    at the top of your program. They'll point out many errors in your program.

    Update:

    $atob is -2.5
    $btoc is -0.5
    $atoc is -3

    That's why the first elsif isn't executed: $btoc > 1 || $btoc < -1 is false.

      my god I'd commented out some stuff at the top of my program as I was having trouble automating excel. And I'd done strict and warnings!!!!! I hang my head in shame and apologies for the waste of your time. Thanks to all who replied E
Re: if logic OR parentheses problem
by Corion (Patriarch) on Oct 26, 2007 at 14:14 UTC

    Adding either of the two lines to your program will make Perl tell you what goes wrong:

    #!/usr/bin/perl -w # or use warnings;

    The -w switch or use warnings; lets Perl tell you what it considers dodgy or unintended practice. For example, comparing two strings that don't look like numbers as numbers. Perl considers atob and atoc to be strings for example, which likely is not what you intended in the first place.

    Adding the following line prohibits the use of barewords as strings, which even more likely prevents you from making mistakes like the one you did. In fact, it prevents so many mistakes like misspelling and reference errors, this line should be at the top of all your Perl programs:

    use strict;

    With that line, Perl tells you that:

    Bareword "atob" not allowed while "strict subs" in use at ...

    which is an immediate hint. Either declare atob as a subroutine, or use $atob, as you propably intended.

Re: if logic OR parentheses problem
by gamache (Friar) on Oct 26, 2007 at 14:18 UTC
    If you add the line:
    print join ' ', $atob, $btoc, $atoc, "\n";
    You'll notice that $atob is -2.5, $btoc is -0.5, and $atoc is -3.

    For clarity, I'd also use the abs function rather than nested logic:

    if (abs $atob > 1 && abs $btoc > 1 && abs $atoc > 1 ) { print OUTFILE "DIFF > 1 all three\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 1; $matrixflags[$row - 2][$i] = 1; } elsif (abs $atob > 1 && abs $btoc < 1 && abs $atoc > 1 ) { print OUTFILE "DIFFA > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 0; $matrixflags[$row - 2][$i] = 0; } elsif ( ... ) { ... }
    And like the other monks suggested, use strict; and use warnings; will point out where your code could run into problems. There is also use diagnostics; for an extra helping of advice.
      print join ' ', $atob, $btoc, $atoc, "\n";

      Why use join? It's far simpler to interpolate inside double-quotes.

      print qq{$atob $btoc $atoc\n};

      Cheers,

      JohnGG

      Update: Corrected sigil typo

        I use join like this all over the place. In many cases, I find that it looks less cluttered in the code. There's no great advantage to it in this case, but there's no reason to avoid it either.
Re: if logic OR parentheses problem
by papidave (Pilgrim) on Oct 26, 2007 at 15:53 UTC
    Others have already discussed the logic for the input values you present at the beginning. I'm more concerned about the general functionality of your code. To be specific, did you really mean to exclude the case where the difference values are equal to 1 from your logic? For those boundary conditions, all of the expressions will fail, because 1 is neither less than nor greater than 1.

    If your /[abc]to[abc]/ vars are intended to describe absolute distances, I would recommend going with the abs() value as previously recommended, then using >=1 or <=1 for one of the two cases. You probably haven't seen it yet if your data is really real, but it could burn you in the future.

Re: if logic OR parentheses problem
by roboticus (Chancellor) on Oct 26, 2007 at 21:41 UTC
    Ellhar:

    It looks like you're overcomplicating things. By looking over your code, it looks like you really want something like this (untested!):

    $a= 20; $b= 22.5; $c= 23 $atob = abs($a - $b) > 1 ? 1 : 0; $btoc = abs($b - $c) > 1 ? 1 : 0; $atoc = abs($a - $c) > 1 ? 1 : 0; if ( $atob && $atoc && $btoc ) { print OUTFILE "DIFF > 1 all three\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 1; $matrixflags[$row - 2][$i] = 1; } ...
    That would also help you avoid some of the impossible conditions in your code, like:

    ((btoc < 1) && (btoc > -1))
    You should always try to simplify your logic before writing your code!

    ...roboticus

    Update: After another second of thought, perhaps this would be even more to your liking--Replace the if .. then stuff with:

    if ($atob+$atoc+$btoc) { printf OUTFILE "DIFF=%d: %f, %f, %f\n", $atob+$atoc+$btoc, $a-$b, $a-$c, $b-$c; } $matrixflags[$row - 4][$i] = $atob; $matrixflags[$row - 3][$i] = $atoc; $matrixflags[$row - 2][$i] = $atob; }
Re: if logic OR parentheses problem
by talexb (Chancellor) on Oct 26, 2007 at 15:03 UTC

    First of all, that isn't your code -- here's what perltidy and the Perl compiler would like it to be:

    #!/usr/bin/perl -w use strict; { my $a = 20; my $b = 22.5; my $c = 23; my $atob = $a - $b; my $btoc = $b - $c; my $atoc = $a - $c; my @matrixflags; if ((($atob > 1) || ($atob < -1)) && (($atoc > 1) || ($atoc < -1)) && (($btoc > 1) || ($btoc < -1))) { print OUTFILE "DIFF > 1 all three\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 1; $matrixflags[$row - 2][$i] = 1; } elsif ((($atob > 1) || ($atob < -1)) && (($btoc < 1) && ($btoc > -1)) && (($atoc > 1) || ($atoc < -1))) { print OUTFILE "DIFFA > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 1; $matrixflags[$row - 3][$i] = 0; $matrixflags[$row - 2][$i] = 0; } elsif ((($atob > 1) || ($atob < -1)) && (($btoc > 1) || ($btoc < -1)) && (($atoc < 1) && ($atoc > -1))) { print OUTFILE "DIFFB > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 0; $matrixflags[$row - 3][$i] = 1; $matrixflags[$row - 2][$i] = 0; } elsif ((($atob < 1) && ($atob > -1)) && (($btoc > 1) || ($btoc < -1)) && (($atoc > 1) || ($atoc < -1))) { print OUTFILE "DIFFC > 1 $atob $atoc $btoc\n"; $matrixflags[$row - 4][$i] = 0; $matrixflags[$row - 3][$i] = 0; $matrixflags[$row - 2][$i] = 1; } #So in this example in my head the 1st elsif should be executed. #Difference $atob = 1.5 so (($atob > 1) || ($atob < -1)) is true. #Difference $btoc = 0.5 so (($btoc < 1) && ($btoc > -1)) is true. #Difference $atoc = 3 so (($atoc > 1) || ($atoc < -1)) is true. }

    Secondly, even that throws errors -- neither $row or $i are defined (either using my or programmatically). Why not show us a fragment of code that at least compiles and runs, then we'll be able to help you.

    Alex / talexb / Toronto

    "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds