So, there seems to be multiple problems with holli's code
- 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.
- 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();
| [reply] [d/l] |