line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
11
|
|
|
11
|
|
227600
|
use strict; |
|
11
|
|
|
|
|
28
|
|
|
11
|
|
|
|
|
521
|
|
2
|
11
|
|
|
11
|
|
66
|
use warnings; |
|
11
|
|
|
|
|
24
|
|
|
11
|
|
|
|
|
1058
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Test::Number::Delta; |
5
|
|
|
|
|
|
|
# ABSTRACT: Compare the difference between numbers against a given tolerance |
6
|
|
|
|
|
|
|
our $VERSION = '1.04'; # VERSION |
7
|
|
|
|
|
|
|
|
8
|
11
|
|
|
11
|
|
74
|
use vars qw (@EXPORT @ISA); |
|
11
|
|
|
|
|
21
|
|
|
11
|
|
|
|
|
930
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Required modules |
11
|
11
|
|
|
11
|
|
62
|
use Carp; |
|
11
|
|
|
|
|
19
|
|
|
11
|
|
|
|
|
898
|
|
12
|
11
|
|
|
11
|
|
20171
|
use Test::Builder; |
|
11
|
|
|
|
|
52364
|
|
|
11
|
|
|
|
|
442
|
|
13
|
11
|
|
|
11
|
|
66
|
use Exporter; |
|
11
|
|
|
|
|
24
|
|
|
11
|
|
|
|
|
31577
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
@ISA = qw( Exporter ); |
16
|
|
|
|
|
|
|
@EXPORT = qw( delta_not_ok delta_ok delta_within delta_not_within ); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $Test = Test::Builder->new; |
20
|
|
|
|
|
|
|
my $Epsilon = 1e-6; |
21
|
|
|
|
|
|
|
my $Relative = undef; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub import { |
24
|
13
|
|
|
13
|
|
9021
|
my $self = shift; |
25
|
13
|
|
|
|
|
50
|
my $pack = caller; |
26
|
13
|
|
|
|
|
305
|
my $found = grep /within|relative/, @_; |
27
|
13
|
100
|
|
|
|
515
|
croak "Can't specify more than one of 'within' or 'relative'" |
28
|
|
|
|
|
|
|
if $found > 1; |
29
|
12
|
100
|
|
|
|
46
|
if ($found) { |
30
|
8
|
|
|
|
|
34
|
my ( $param, $value ) = splice @_, 0, 2; |
31
|
8
|
100
|
|
|
|
12528
|
croak "'$param' parameter must be non-zero" |
32
|
|
|
|
|
|
|
if $value == 0; |
33
|
6
|
100
|
|
|
|
33
|
if ( $param eq 'within' ) { |
|
|
100
|
|
|
|
|
|
34
|
3
|
|
|
|
|
8
|
$Epsilon = abs($value); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
elsif ( $param eq 'relative' ) { |
37
|
2
|
|
|
|
|
8
|
$Relative = abs($value); |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
else { |
40
|
1
|
|
|
|
|
313
|
croak "Test::Number::Delta parameters must come first"; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
} |
43
|
9
|
|
|
|
|
57
|
$Test->exported_to($pack); |
44
|
9
|
|
|
|
|
100
|
$Test->plan(@_); |
45
|
9
|
|
|
|
|
38811
|
$self->export_to_level( 1, $self, $_ ) for @EXPORT; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
49
|
|
|
|
|
|
|
# _check -- recursive function to perform comparison |
50
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub _check { |
53
|
106
|
|
|
106
|
|
185
|
my ( $p, $q, $epsilon, $name, @indices ) = @_; |
54
|
106
|
|
|
|
|
260
|
my ( $ok, $diag ) = ( 1, q{} ); # assume true |
55
|
106
|
100
|
66
|
|
|
452
|
if ( ref $p eq 'ARRAY' || ref $q eq 'ARRAY' ) { |
56
|
28
|
100
|
|
|
|
51
|
if ( @$p == @$q ) { |
57
|
27
|
|
|
|
|
30
|
for my $i ( 0 .. $#{$p} ) { |
|
27
|
|
|
|
|
653
|
|
58
|
50
|
|
|
|
|
52
|
my @new_indices; |
59
|
50
|
100
|
|
|
|
161
|
( $ok, $diag, @new_indices ) = _check( $p->[$i], $q->[$i], $epsilon, $name, |
60
|
|
|
|
|
|
|
scalar @indices ? @indices : (), $i, ); |
61
|
50
|
100
|
|
|
|
145
|
if ( not $ok ) { |
62
|
10
|
|
|
|
|
15
|
@indices = @new_indices; |
63
|
10
|
|
|
|
|
19
|
last; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
else { |
68
|
1
|
|
|
|
|
2
|
$ok = 0; |
69
|
1
|
|
|
|
|
4
|
$diag = |
70
|
|
|
|
|
|
|
"Got an array of length " |
71
|
|
|
|
|
|
|
. scalar(@$p) |
72
|
|
|
|
|
|
|
. ", but expected an array of length " |
73
|
|
|
|
|
|
|
. scalar(@$q); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
else { |
77
|
78
|
|
|
|
|
157
|
$ok = abs( $p - $q ) < $epsilon; |
78
|
78
|
100
|
|
|
|
152
|
if ( !$ok ) { |
79
|
26
|
|
|
|
|
55
|
my ( $ep, $dp ) = _ep_dp($epsilon); |
80
|
26
|
|
|
|
|
295
|
$diag = sprintf( "%.${dp}f and %.${dp}f are not equal" . " to within %.${ep}f", |
81
|
|
|
|
|
|
|
$p, $q, $epsilon ); |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
} |
84
|
106
|
100
|
|
|
|
566
|
return ( $ok, $diag, scalar(@indices) ? @indices : () ); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub _ep_dp { |
88
|
50
|
|
|
50
|
|
69
|
my $epsilon = shift; |
89
|
50
|
|
|
|
|
527
|
my ($exp) = sprintf( "%e", $epsilon ) =~ m/e(.+)/; |
90
|
50
|
100
|
|
|
|
151
|
my $ep = $exp < 0 ? -$exp : 1; |
91
|
50
|
|
|
|
|
76
|
my $dp = $ep + 1; |
92
|
50
|
|
|
|
|
102
|
return ( $ep, $dp ); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
97
|
|
|
|
|
|
|
# delta_within() |
98
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub delta_within($$$;$) { ## no critic |
102
|
33
|
|
|
33
|
1
|
9787
|
my ( $p, $q, $epsilon, $name ) = @_; |
103
|
33
|
100
|
|
|
|
378
|
croak "Value of epsilon to delta_within must be non-zero" |
104
|
|
|
|
|
|
|
if $epsilon == 0; |
105
|
32
|
|
|
|
|
49
|
$epsilon = abs($epsilon); |
106
|
32
|
|
|
|
|
82
|
my ( $ok, $diag, @indices ) = _check( $p, $q, $epsilon, $name ); |
107
|
32
|
100
|
|
|
|
143
|
if (@indices) { |
108
|
3
|
|
|
|
|
12
|
$diag = "At [" . join( "][", @indices ) . "]: $diag"; |
109
|
|
|
|
|
|
|
} |
110
|
32
|
|
66
|
|
|
135
|
return $Test->ok( $ok, $name ) || $Test->diag($diag); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
114
|
|
|
|
|
|
|
# delta_ok() |
115
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub delta_ok($$;$) { ## no critic |
119
|
26
|
|
|
26
|
1
|
24311
|
my ( $p, $q, $name ) = @_; |
120
|
|
|
|
|
|
|
{ |
121
|
26
|
|
|
|
|
44
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
|
26
|
|
|
|
|
51
|
|
122
|
26
|
100
|
|
|
|
110
|
my $e = |
|
|
100
|
|
|
|
|
|
123
|
|
|
|
|
|
|
$Relative |
124
|
|
|
|
|
|
|
? $Relative * ( abs($p) > abs($q) ? abs($p) : abs($q) ) |
125
|
|
|
|
|
|
|
: $Epsilon; |
126
|
26
|
|
|
|
|
73
|
delta_within( $p, $q, $e, $name ); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
131
|
|
|
|
|
|
|
# delta_not_ok() |
132
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub delta_not_within($$$;$) { ## no critic |
136
|
25
|
|
|
25
|
1
|
7680
|
my ( $p, $q, $epsilon, $name ) = @_; |
137
|
25
|
100
|
|
|
|
1255
|
croak "Value of epsilon to delta_not_within must be non-zero" |
138
|
|
|
|
|
|
|
if $epsilon == 0; |
139
|
24
|
|
|
|
|
29
|
$epsilon = abs($epsilon); |
140
|
24
|
|
|
|
|
49
|
my ( $ok, undef, @indices ) = _check( $p, $q, $epsilon, $name ); |
141
|
24
|
|
|
|
|
38
|
$ok = !$ok; |
142
|
24
|
|
|
|
|
594
|
my ( $ep, $dp ) = _ep_dp($epsilon); |
143
|
24
|
|
|
|
|
160
|
my $diag = sprintf( "Arguments are equal to within %.${ep}f", $epsilon ); |
144
|
24
|
|
66
|
|
|
83
|
return $Test->ok( $ok, $name ) || $Test->diag($diag); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub delta_not_ok($$;$) { ## no critic |
149
|
18
|
|
|
18
|
1
|
18734
|
my ( $p, $q, $name ) = @_; |
150
|
|
|
|
|
|
|
{ |
151
|
18
|
|
|
|
|
51
|
local $Test::Builder::Level = $Test::Builder::Level + 1; |
|
18
|
|
|
|
|
30
|
|
152
|
18
|
100
|
|
|
|
62
|
my $e = |
|
|
100
|
|
|
|
|
|
153
|
|
|
|
|
|
|
$Relative |
154
|
|
|
|
|
|
|
? $Relative * ( abs($p) > abs($q) ? abs($p) : abs($q) ) |
155
|
|
|
|
|
|
|
: $Epsilon; |
156
|
18
|
|
|
|
|
42
|
delta_not_within( $p, $q, $e, $name ); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
1; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
__END__ |