in reply to Re: IF condition with a range
in thread IF condition with a range

I was wondering, how do you go about in the following scenario?
* if it is equal, do something
* if it is equal or within +/- 1 do something else
Because I think that, if you put these statements in sequential "ifs", then the second one does not find the exact equal matches (they are already greped in the first conditional if).

Replies are listed 'Best First'.
Re^3: IF condition with a range
by tobyink (Canon) on Jul 17, 2018 at 08:42 UTC

    You're thinking of something like this:

    if ( it is equal ) { do something; } elsif ( it is equal or close ) { do something else; }

    But you want:

    if ( it is equal ) { do something; } if ( it is equal or close ) { do something else; }

    Or even:

    if ( it is equal or close ) { if ( it is equal ) { do something; } do something else; }
      Aha, so you mean I should have only ifs and not if-elseif. Good, I will try that!
        Aha, so you mean I should have only ifs and not if-elseif.

        Note that there is a potential pitfall of if (...) {...} if (...) {...} instead of if (...) { if (...) { ... } ... } - it's easy to make a mistake with the logic:

        if ( /^[brc]at$/ ) { # match "bat", "rat", or "cat" print "It's an animal\n"; if ( /^b/ ) { print "... and it flies!\n"; } }

        This is not the same as:

        if ( /^[brc]at$/ ) { print "It's an animal\n"; } if ( /^b/ ) { print "... and it flies!\n"; }

        Because the latter will match any word that starts with b.

        Of course, in this case, it seems obvious that if the numbers are equal, they will also be within +/- 1 of each other, but mistakes like the above can happen if you don't think the logic through (and test it!).

        Update: For example, consider the special case of Inf that syphilis suggested, which I've now added as a test case to my other post.

Re^3: IF condition with a range (updated)
by haukex (Archbishop) on Jul 17, 2018 at 08:48 UTC

    To build on tobyink's post, remember that it's easy to try things out:

    Updated with the Inf test case suggested by syphilis.

    use warnings; use strict; my @testcases = ( [1,-1], [1,0], [1,1], [1,2], [1,3], [9**9999,9**9999] ); for my $sub (qw/ doit1 doit2 doit3 doit4 /) { print "-----\n"; for my $testcase (@testcases) { print "$sub($testcase->[0], $testcase->[1]):\n"; # for this test only, not recommended otherwise: no strict 'refs'; &{$sub}(@$testcase); } } sub doit1 { my ($x,$y) = @_; if ($x==$y) { print "\tThey are equal, do something\n"; } if (abs($y-$x)<=1) { print "\tThey are within +/- 1, do something else\n"; } } sub doit2 { my ($x,$y) = @_; if ($x==$y) { print "\tThey are equal, do something\n"; } elsif (abs($y-$x)<=1) { print "\tThey are within +/- 1, do something else\n"; } } sub doit3 { my ($x,$y) = @_; if (abs($y-$x)<=1) { print "\tThey are within +/- 1, do something else\n"; } elsif ($x==$y) { print "\tThey are equal, do something\n"; } } sub doit4 { my ($x,$y) = @_; if (abs($y-$x)<=1) { if ($x==$y) { print "\tThey are equal, do something\n"; } print "\tThey are within +/- 1, do something else\n"; } } __END__ ----- doit1(1, -1): doit1(1, 0): They are within +/- 1, do something else doit1(1, 1): They are equal, do something They are within +/- 1, do something else doit1(1, 2): They are within +/- 1, do something else doit1(1, 3): doit1(Inf, Inf): They are equal, do something ----- doit2(1, -1): doit2(1, 0): They are within +/- 1, do something else doit2(1, 1): They are equal, do something doit2(1, 2): They are within +/- 1, do something else doit2(1, 3): doit2(Inf, Inf): They are equal, do something ----- doit3(1, -1): doit3(1, 0): They are within +/- 1, do something else doit3(1, 1): They are within +/- 1, do something else doit3(1, 2): They are within +/- 1, do something else doit3(1, 3): doit3(Inf, Inf): They are equal, do something ----- doit4(1, -1): doit4(1, 0): They are within +/- 1, do something else doit4(1, 1): They are equal, do something They are within +/- 1, do something else doit4(1, 2): They are within +/- 1, do something else doit4(1, 3): doit4(Inf, Inf):

      Frankly with Inf, it's probably a good thing if your code doesn't treat two infinite values as being equal.

      my $x = 6**6**6; # Inf my $y = 7**7**7; # Inf print "equal\n" if $x==$y; # says "equal" even though mathematically +they are not
        Frankly with Inf, it's probably a good thing if your code doesn't treat two infinite values as being equal

        That's a rather novel approach to overflow, and one that I would discourage.

        Similarly, wrt to underflow, one could then say:

        Frankly with 0, it's probably a good thing if your code doesn't treat two zero values as being equal.

        my $x = 1e-5000; # 0
        my $y = 1e-5100; # 0

        print "equal\n" if $x==$y; # says "equal" even though mathematically they are not

        That's also an approach that I would discourage.

        Cheers,
        Rob