Skip to content

Commit bff5a5b

Browse files
committed
Revert "simplify some calculations" as causes numerical problems, fix variance to >= 0 - fix #34
1 parent b5e20d4 commit bff5a5b

File tree

3 files changed

+21
-6
lines changed

3 files changed

+21
-6
lines changed

Changes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- fix recent change that allowed negative variance and standard deviation (#34) - thanks @shawnlaffan for report
2+
13
0.854 2025-02-25
24
- fix anova_rptd problem depending on grouping of IVs (part of RT#97925)
35
- do all plotting with PDL::Graphics::Simple

lib/PDL/Stats/Basic.pd

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ pp_def('stdv',
5959
a2 += $a() * $a();
6060
%}
6161
if (N < 1) { $SETBAD(b()); continue; }
62-
$b() = sqrt( (a2 - sa*sa/N) / N );
62+
$GENERIC() var = a2 / N - (sa/N)*(sa/N);
63+
if (var < 0) var = 0;
64+
$b() = sqrt(var);
6365
',
6466
Doc => 'Sample standard deviation.',
6567
);
@@ -77,7 +79,9 @@ pp_def('stdv_unbiased',
7779
a2 += $a() * $a();
7880
%}
7981
if (N < 2) { $SETBAD(b()); continue; }
80-
$b() = pow( (a2 - sa*sa/N) / (N-1), .5 );
82+
$GENERIC() var = a2/(N-1) - sa*sa/(N*(N-1));
83+
if (var < 0) var = 0;
84+
$b() = sqrt(var);
8185
',
8286
Doc => 'Unbiased estimate of population standard deviation.',
8387
);
@@ -95,7 +99,7 @@ pp_def('var',
9599
a2 += $a() * $a();
96100
%}
97101
if (N < 1) { $SETBAD(b()); continue; }
98-
$b() = (a2 - sa*sa/N) / N;
102+
$b() = a2 / N - sa*sa/(N*N);
99103
',
100104
Doc => 'Sample variance.',
101105
);
@@ -130,8 +134,9 @@ pp_def('se',
130134
sa += $a();
131135
a2 += $a() * $a();
132136
%}
133-
if (N < 2) { $SETBAD(b()); continue; }
134-
$b() = sqrt( (a2 - sa*sa/N) / (N*(N-1)) );
137+
$GENERIC() se2 = (a2 - sa*sa/N) / (N*(N-1));
138+
if (se2 < 0) se2 = 0;
139+
$b() = sqrt(se2);
135140
',
136141
Doc => '
137142
=for ref
@@ -275,7 +280,7 @@ pp_def('cov',
275280
sb += $b();
276281
%}
277282
if (N < 1) { $SETBAD(c()); continue; }
278-
$c() = (ab - sa*sb/N) / N;
283+
$c() = ab / N - (sa/N) * (sb/N);
279284
',
280285
Doc => 'Sample covariance. see B<corr> for ways to call',
281286
);

t/basic.t

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ is_pdl $a->skew_unbiased, pdl( 0 ), "unbiased sample skewness of $a";
1818
is_pdl $a->kurt, pdl( -1.3 ), "sample kurtosis of $a";
1919
is_pdl $a->kurt_unbiased, pdl( -1.2 ), "unbiased sample kurtosis of $a";
2020

21+
{
22+
my $x = pdl [(0.001) x 6];
23+
my $var = $x->var;
24+
ok $var >= 0, 'var >= 0' or diag "var = $var";
25+
my $stdv = $x->stdv;
26+
ok $stdv >= 0, 'stdv >= 0' or diag "stdv = $stdv";
27+
}
28+
2129
is_pdl $_->ss, (($_ - $_->avg)**2)->sumover, "ss for $_" for
2230
pdl('[1 1 1 1 2 3 4 4 4 4 4 4]'),
2331
pdl('[1 2 2 2 3 3 3 3 4 4 5 5]'),

0 commit comments

Comments
 (0)