in reply to Re^6: Why does my get_max_index function return zero? (High Water Mark Algorithm)
in thread Why does my get_max_index function return zero? (High Water Mark Algorithm)

Wow! I've looking at this and admit that I am at a loss to understand how it works. I see that it does indeed work, but even with some extra print statements, I'm not sure exactly how.

I'd appreciate some enlightenment. ($0 .. !$0) is truly bizarre looking!
update: How does the scalar value of the weird looking range wind up being one less when the "if statement" is satisfied as opposed to what it is before the if statement? Of course $0 is normally the file name of the executing Perl script (C:/...baha/../../this.pl) I don't understand the meaning of ($0 .. !$0).

use strict; use warnings; $|=1; # turn of stdout buffering sub get_max_index { my $imax = 0; foreach (@_) { print "b4 if: default var = $_ imax=$imax\n"; print "b4 if: Value of weird range=".($0 .. !$0),"\n"; $imax = ($0 .. !$0), print "If triggered, new imax=$imax\n" if + $_ > $_[$imax]; print "\n"; } return $imax; } my @arr = (1,2,13,4,5); my $ans = get_max_index(@arr); print"$ans\n"; #2 __END__ b4 if: default var = 1 imax=0 b4 if: Value of weird range=1 b4 if: default var = 2 imax=0 b4 if: Value of weird range=2 If triggered, new imax=1 b4 if: default var = 13 imax=1 b4 if: Value of weird range=3 If triggered, new imax=2 b4 if: default var = 4 imax=2 b4 if: Value of weird range=4 b4 if: default var = 5 imax=2 b4 if: Value of weird range=5 2

Replies are listed 'Best First'.
Re^8: Why does my get_max_index function return zero? (High Water Mark Algorithm)
by pryrt (Abbot) on Jun 09, 2019 at 19:02 UTC
    I am at a loss to understand how it works

    I was, too... though I'm closer than I was when it was first posted. After some more experimenting and reading on the flip-flop, here's what I think is happening. $0 will always be true, and thus !$0 will always be false. So the flipflop statement is thus TRUE .. FALSE. Since perlop says, "The value returned is either the empty string for false, or a sequence number (beginning with 1) for true", then the .. will start counting up, and since !$0 is always false, will never stop counting.

    My mental thinking is still wrong, however, because I'm still seeing an off-by-one error. On the second instance of that loop, I would expect the .. to return a 2, not a 1 -- as you showed, weird range was 2, but imax was 1...

      Whoops!
      I still don't quite get it. Will look again at previous threads... This is obtuse, wild stuff!

      I see the "off by one error" and that's weird.

        So, there seems to be multiple problems with holli's code

        1. Because the .. flip-flop holds its state between calls to the function, if you run holli's function twice with the same data set, the second will always fail.
        2. It seems that because the "if" conditional inhibits when the flip-flop increments its counter, there are many (most) situations where it won't work.
          • As AnomalousMonk pointed out here, data sets like (1,2,13,4,5, 99) don't work: this is because the "if" only triggers twice, on 13 and 99. (On first reading, or even second, I hadn't realized AnomalousMonk was trying to show a data set that didn't work; I hadn't understood the point that was being made, and I misinterpreted it as a counterpoint to what Marshall said, rather than an example of data that failed the algorithm)
          • If the data were (1,0,13,4,5) instead, it wouldn't have worked either, because the if didn't trigger on the 0, so the flip-flop hits 1 with 13, rather than 2.

        The only way that the flip-flop will work as the counter is if the FF is run every time, but imax only increased sometimes... and then the ff shows off-by-one, because it starts at 1, so you have to correct for that. And my solution involved a separate variable to hold the ff state, which means it would have been better to just use a counter-variable to begin with. And my variant still doesn't solve the problem of multiple calls not resetting the ff state.

        here's some example code which shows some of those above:

        use strict; use warnings; use Test::More; $| = 1; sub holli { my $imax = 0; foreach (@_) { $imax = ($0 .. !$0) if $_ > $_[$imax]; } return $imax; } is( holli(1,2,13,4,5), 2, "holli(1,2,13,4,5): seems to work"); is( holli(1,2,13,4,5), 2, "holli(1,2,13,4,5): except that if you run i +t a second time, it will fail, because ff holds its state from last i +nstance"); is( do{local @_ = (1,2,13,4,5); my $imax=0; foreach(@_){$imax = ($0..! +$0) if $_>$_[$imax]}; $imax }, 2, "do(1,2,13,4,5): same data set, but + use a local do{} instead of the function to avoid the again bug"); is( do{local @_ = (1,2,13,4,5,99); my $imax=0; foreach(@_){$imax = ($0 +..!$0) if $_>$_[$imax]}; $imax }, 5, "AnomalousMonk(1,2,13,4,5,99): t +his data set fails, I think because"); is( do{local @_ = (3,2,1,3,2,1,3,2,1,15); my $imax=0; foreach(@_){$ima +x = ($0..!$0) if $_>$_[$imax]}; $imax }, 9, '(3,2,15): should be 9, b +ut is 1, because ff-if-cond only triggers once'); is( do{local @_ = (1,0,13); my $imax=0; foreach(@_){$imax = ($0..!$0) +if $_>$_[$imax]}; $imax }, 2, "do(1,0,13): second element is lower ra +ther than higher than first, so third is the first time that if-then- +ff triggers"); is( do{local @_ = (1,0,13,4); my $imax=0; foreach(@_){$imax = ($0..!$0 +) if $_>$_[$imax]}; $imax }, 2, "do(1,0,13,4): you would think this w +ould fail, too... but because \$_=4 happens to be greater than \$_[\$ +imax]=\$_[1]=0, it fakes it into passing, because of where values end +ed up."); ### here's my updated algorithm, to fix the couting errors and off-by- +one, but it does not fix the hold-state-between-runs ### ### also, note, I couldn't come up with a way to run the flipflop ever +y time, but assign to imax only on conditional, without storing the f +f result in a separate counter... in which case, the counter-based lo +ops make more sense than a flipflop anyway. is( do{ local @_ = (1,2,13,4,5); my $imax=0; foreach(@_){my$ff = $0 .. + !$0; $imax = $ff-1 if $_ > $_[$imax]}; $imax;}, 2, "pryrt: do(1,2,13 +,4,5)" ); is( do{ local @_ = (1,2,13,4,5,99); my $imax=0; foreach(@_){my$ff = $0 + .. !$0; $imax = $ff-1 if $_ > $_[$imax]}; $imax;}, 5, "pryrt: do(1,2 +,13,4,5,99)" ); is( do{ local @_ = (3,2,1,3,2,1,3,2,1,15); my $imax=0; foreach(@_){my$ +ff = $0 .. !$0; $imax = $ff-1 if $_ > $_[$imax]}; $imax;}, 9, "pryrt: + do(3,2,1,3,2,1,3,2,1,15)" ); is( do{ local @_ = (1,0,13); my $imax=0; foreach(@_){my$ff = $0 .. !$0 +; $imax = $ff-1 if $_ > $_[$imax]}; $imax;}, 2, "pryrt: do(1,0,13)" ) +; is( do{ local @_ = (1,0,13,4); my $imax=0; foreach(@_){my$ff = $0 .. ! +$0; $imax = $ff-1 if $_ > $_[$imax]}; $imax;}, 2, "pryrt: do(1,0,13,4 +)" ); done_testing();

Re^8: Why does my get_max_index function return zero? (High Water Mark Algorithm)
by holli (Abbot) on Jun 09, 2019 at 17:36 UTC
    C:\berrybrew\5.30.0_64>perl -e "$foo = 'something true-ish'; foreach ( +0..9) { $bar = ($foo .. !$foo); print qq($bar:); }" 1:2:3:4:5:6:7:8:9:10:


    holli

    You can lead your users to water, but alas, you cannot drown them.
Re^8: Why does my get_max_index function return zero? (High Water Mark Algorithm)
by AnomalousMonk (Archbishop) on Jun 09, 2019 at 18:09 UTC

    But note also:

    c:\@Work\Perl\monks>perl -wMstrict -le "sub get_max_index { my $imax = 0; foreach (@_) { $imax = ($0 .. !$0) if $_ > $_[$imax]; print 'imax ', $imax; } return $imax; } my @arr = (1,2,13,4,5, 99); my $ans = get_max_index(@arr); print $ans; " imax 0 imax 1 imax 2 imax 2 imax 2 imax 3 3


    Give a man a fish:  <%-{-{-{-<