line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::IntervalSearch; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
require 5.004_01; |
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
2746
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
83
|
|
6
|
2
|
|
|
2
|
|
11
|
use vars qw(@EXPORT_OK @ISA $VERSION); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
122
|
|
7
|
2
|
|
|
2
|
|
14
|
use Exporter; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
79
|
|
8
|
2
|
|
|
2
|
|
10
|
use Carp; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
4170
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
@EXPORT_OK = qw(interval_search); |
11
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
12
|
|
|
|
|
|
|
$VERSION = 1.06; |
13
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
14
|
|
|
|
|
|
|
|
15
|
0
|
|
|
0
|
0
|
0
|
sub cluck { warn Carp::longmess @_ } |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub LessThan { |
18
|
17080
|
|
|
17080
|
0
|
60114
|
$_[0] < $_[1]; |
19
|
|
|
|
|
|
|
} |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub LessThanEqualTo { |
22
|
12043
|
|
|
12043
|
0
|
35406
|
$_[0] <= $_[1]; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# This holds the result from the last interval search. |
26
|
|
|
|
|
|
|
my $last_interval_result = undef; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub interval_search { |
29
|
5517
|
50
|
|
5517
|
1
|
36091
|
if ( @_ > 4 ) { |
30
|
0
|
|
|
|
|
0
|
cluck "interval called with too many parameters"; |
31
|
0
|
|
|
|
|
0
|
return; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Get the input arguments. |
35
|
5517
|
|
|
|
|
6926
|
my $x = shift; |
36
|
5517
|
|
|
|
|
6247
|
my $sequenceRef = shift; |
37
|
|
|
|
|
|
|
|
38
|
5517
|
100
|
|
|
|
10436
|
return unless defined($x); |
39
|
5516
|
100
|
|
|
|
15370
|
return unless defined($sequenceRef); |
40
|
5515
|
100
|
|
|
|
10275
|
return unless ref($sequenceRef); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Check the input arguments for any code references and use them. |
43
|
5514
|
|
|
|
|
7753
|
my $LessThan = \&LessThan; |
44
|
5514
|
|
|
|
|
7330
|
my $LessThanEqualTo = \&LessThanEqualTo; |
45
|
5514
|
50
|
66
|
|
|
14755
|
@_ and defined(ref($_[0])) and ref($_[0]) eq 'CODE' and |
|
|
|
66
|
|
|
|
|
46
|
|
|
|
|
|
|
$LessThan = shift; |
47
|
5514
|
50
|
66
|
|
|
22588
|
@_ and defined(ref($_[0])) and ref($_[0]) eq 'CODE' and |
|
|
|
66
|
|
|
|
|
48
|
|
|
|
|
|
|
$LessThanEqualTo = shift; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# Get the number of points in the data. |
51
|
5514
|
|
|
|
|
6531
|
my $num = @$sequenceRef; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Return -1 if there's no data. |
54
|
5514
|
100
|
|
|
|
10032
|
if ( $num <= 0 ) { |
55
|
2
|
|
|
|
|
3
|
$last_interval_result = 0; |
56
|
2
|
|
|
|
|
7
|
return -1; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Use the result from the last time through the subroutine, if it |
60
|
|
|
|
|
|
|
# exists. Force the result into the range required by the array |
61
|
|
|
|
|
|
|
# size. |
62
|
5512
|
100
|
|
|
|
9776
|
$last_interval_result = 0 unless defined($last_interval_result); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Which side of the data point is x on if there's only one point? |
65
|
5512
|
100
|
|
|
|
9557
|
if ( $num == 1 ) { |
66
|
1
|
|
|
|
|
1
|
$last_interval_result = 0; |
67
|
1
|
50
|
|
|
|
4
|
if ( &$LessThan($x, $sequenceRef->[0]) ) { |
68
|
1
|
|
|
|
|
3
|
return -1; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
else { |
71
|
0
|
|
|
|
|
0
|
return 0; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Is the point less than the smallest point in the sequence? |
76
|
5511
|
100
|
|
|
|
12017
|
if ( &$LessThan($x, $sequenceRef->[0]) ) { |
77
|
181
|
|
|
|
|
402
|
$last_interval_result = 0; |
78
|
181
|
|
|
|
|
484
|
return -1; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Is the point greater than the largest point in the sequence? |
82
|
5330
|
100
|
|
|
|
13550
|
if ( &$LessThanEqualTo($sequenceRef->[$num-1], $x) ) { |
83
|
171
|
|
|
|
|
678
|
return $last_interval_result = $num - 1; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Use the result from the last run as a start for this run. |
87
|
5159
|
50
|
|
|
|
11489
|
if ( $last_interval_result > $num-1 ) { |
88
|
0
|
|
|
|
|
0
|
$last_interval_result = $num - 2; |
89
|
|
|
|
|
|
|
} |
90
|
5159
|
|
|
|
|
5893
|
my $ilo = $last_interval_result; |
91
|
5159
|
|
|
|
|
6539
|
my $ihi = $ilo + 1; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Is the new upper ihi beyond the extent of the sequence? |
94
|
5159
|
100
|
|
|
|
9606
|
if ( $ihi >= $num ) { |
95
|
111
|
|
|
|
|
116
|
$ihi = $num - 1; |
96
|
111
|
|
|
|
|
135
|
$ilo = $ihi - 1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# If x < sequence(ilo), then decrease ilo to capture x. |
100
|
5159
|
100
|
|
|
|
9812
|
if ( &$LessThan($x, $sequenceRef->[$ilo]) ) { |
101
|
558
|
|
|
|
|
1121
|
my $istep = 1; |
102
|
558
|
|
|
|
|
596
|
for (;;) { |
103
|
3855
|
|
|
|
|
4081
|
$ihi = $ilo; |
104
|
3855
|
|
|
|
|
4075
|
$ilo = $ihi - $istep; |
105
|
3855
|
100
|
|
|
|
8014
|
if ( $ilo <= 0 ) { |
106
|
192
|
|
|
|
|
202
|
$ilo = 0; |
107
|
192
|
|
|
|
|
276
|
last; |
108
|
|
|
|
|
|
|
} |
109
|
3663
|
100
|
|
|
|
6748
|
if ( &$LessThanEqualTo($sequenceRef->[$ilo], $x) ) { |
110
|
366
|
|
|
|
|
828
|
last; |
111
|
|
|
|
|
|
|
} |
112
|
3297
|
|
|
|
|
7103
|
$istep *= 2; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# If x >= sequence(ihi), then increase ihi to capture x. |
117
|
5159
|
100
|
|
|
|
10115
|
if ( &$LessThanEqualTo($sequenceRef->[$ihi], $x) ) { |
118
|
600
|
|
|
|
|
1128
|
my $istep = 1; |
119
|
600
|
|
|
|
|
677
|
for (;;) { |
120
|
4066
|
|
|
|
|
4310
|
$ilo = $ihi; |
121
|
4066
|
|
|
|
|
4301
|
$ihi = $ilo + $istep; |
122
|
4066
|
100
|
|
|
|
7274
|
if ( $ihi >= $num-1 ) { |
123
|
200
|
|
|
|
|
209
|
$ihi = $num - 1; |
124
|
200
|
|
|
|
|
278
|
last; |
125
|
|
|
|
|
|
|
} |
126
|
3866
|
100
|
|
|
|
6864
|
if ( &$LessThan($x, $sequenceRef->[$ihi]) ) { |
127
|
400
|
|
|
|
|
899
|
last; |
128
|
|
|
|
|
|
|
} |
129
|
3466
|
|
|
|
|
10146
|
$istep *= 2; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Now sequence(ilo) <= x < sequence(ihi). Narrow the interval. |
134
|
5159
|
|
|
|
|
7059
|
for (;;) { |
135
|
|
|
|
|
|
|
# Find the middle point of the sequence. |
136
|
11708
|
|
|
|
|
18106
|
my $middle = int(($ilo + $ihi)/2); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# The division above was integer, so if ihi = ilo+1, then |
139
|
|
|
|
|
|
|
# middle=ilo, which tests if x has been trapped. |
140
|
11708
|
100
|
|
|
|
23568
|
if ( $middle == $ilo ) { |
141
|
5159
|
|
|
|
|
5441
|
$last_interval_result = $ilo; |
142
|
5159
|
|
|
|
|
17407
|
return $ilo; |
143
|
|
|
|
|
|
|
} |
144
|
6549
|
100
|
|
|
|
11811
|
if ( &$LessThan($x, $sequenceRef->[$middle]) ) { |
145
|
3145
|
|
|
|
|
8880
|
$ihi = $middle; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
else { |
148
|
3404
|
|
|
|
|
7870
|
$ilo = $middle; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
1; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
__END__ |