File: chi.pl

package info (click to toggle)
libosl 0.8.0-4.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,328 kB
  • sloc: cpp: 114,345; ruby: 1,290; ansic: 915; makefile: 431; perl: 309; sh: 35
file content (61 lines) | stat: -rwxr-xr-x 1,869 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/perl -w
use strict;
use Getopt::Std;
my %options=();
getopts("t:w:p:s:",\%options);

my $total = $options{t} ? $options{t} : 20;
my $win   = defined $options{w} ? $options{w} : $total/2;
my $p     = defined $options{p} ? $options{p} : 0.5;
#my $significance = $options{'s'} ? $options{'s'} : 0.05;

# XXX: must be compatible with $chi2_threshold
my $significance = 0.05;
#my $chi2_threshold = 6.63490; # for 1%
my $chi2_threshold = 3.84146; # for 5%
#my $chi2_threshold = 2.70554; # for 10%

printf "%4d / %4d \t... %s\n",
    $win, $total, (&is_significant($win, $p, $total) ? "*" : "");
printf "%4d / %4d\tfor significance %f\n",
    &significant_win($p, $total), $total, $significance;
printf "[%f : %f ]\tfor significance %f\n",
    &significant_prob($total, $win, $significance),
    1.0 - &significant_prob($total, $total-$win, $significance), $significance;

sub significant_win($$) {
    my ($p, $total) = @_;
    for (my $i=$total;  $i>=($total*$p); --$i) {
	if (! &is_significant($i, $p, $total)) {
	    return $i+1;
	}
    }
    return $total;
}

sub is_significant($$$) {
    my ($win, $p, $total) = @_;
    my $expected_win = $total*$p;
    my $expected_lose = $total - $expected_win;
    my $lose = $total - $win;
    my $chi = 1.0*($expected_win - $win)*($expected_win - $win)/$expected_win
	+ 1.0*($expected_lose - $lose)*($expected_lose - $lose)/$expected_lose;
    return $chi > $chi2_threshold;
}

sub significant_prob ($$$) {
    my ($total, $win, $significance) = @_;
    my $last_significant = 0.0;
    my $step = 1; # 1.0/$step is used
    while ($step <= 128) {
	for (my $i=1; $last_significant*$step+$i<$step; ++$i) {
	    my $p=($step*$last_significant + $i) / $step;
	    last
		if (($win/$total < $p)
		    || ! is_significant($win, $p, $total));
	    $last_significant = $p;
	}
	$step *= 2;
    }
    return $last_significant;
}