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