1
2
3
4
5
6
7
8
9
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14#include <malloc.h>
15#include <string.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18
19
20double *
21readdoubles(FILE *fp, int *number)
22{
23 struct stat info;
24 double *x;
25 int limit;
26 int n=0, i;
27
28 if (!fstat(fileno(fp), &info) &&
29 info.st_size > 0) {
30 limit = 2*info.st_size/sizeof(double);
31 } else {
32 limit = 10000;
33 }
34
35 x = calloc(limit, sizeof(double));
36 if (!x) {
37 perror("double alloc");
38 exit(3);
39 }
40
41 for (i=0; i<limit; ++i){
42 if (fscanf(fp, "%lf", &x[i]) != 1 ||
43 feof(fp))
44 break;
45 ++n;
46 }
47 *number = n;
48 return x;
49}
50
51void
52arraystats(double *x, int limit, double *mu, double *sigma, double *rho)
53{
54 int n=0, i;
55 double sumsquare=0.0, sum=0.0, top=0.0;
56 double sigma2=0.0;
57
58 for (i=0; i<limit; ++i){
59 sumsquare += x[i]*x[i];
60 sum += x[i];
61 ++n;
62 }
63 *mu = sum/(double)n;
64 *sigma = sqrt((sumsquare - (double)n*(*mu)*(*mu))/(double)(n-1));
65
66 for (i=1; i < n; ++i){
67 top += ((double)x[i]- *mu)*((double)x[i-1]- *mu);
68 sigma2 += ((double)x[i-1] - *mu)*((double)x[i-1] - *mu);
69
70 }
71 *rho = top/sigma2;
72}
73
74
75
76
77
78
79#define TABLESIZE 16384/4
80#define TABLEFACTOR 8192
81#ifndef MINSHORT
82#define MINSHORT -32768
83#define MAXSHORT 32767
84#endif
85
86
87
88
89#define DISTTABLEDOMAIN ((MAXSHORT/TABLEFACTOR)+1)
90#define DISTTABLEGRANULARITY 50000
91#define DISTTABLESIZE (DISTTABLEDOMAIN*DISTTABLEGRANULARITY*2)
92
93static int *
94makedist(double *x, int limit, double mu, double sigma)
95{
96 int *table;
97 int i, index, first=DISTTABLESIZE, last=0;
98 double input;
99
100 table = calloc(DISTTABLESIZE, sizeof(int));
101 if (!table) {
102 perror("table alloc");
103 exit(3);
104 }
105
106 for (i=0; i < limit; ++i) {
107
108 input = (x[i]-mu)/sigma;
109
110 index = (int)rint((input+DISTTABLEDOMAIN)*DISTTABLEGRANULARITY);
111 if (index < 0) index = 0;
112 if (index >= DISTTABLESIZE) index = DISTTABLESIZE-1;
113 ++table[index];
114 if (index > last)
115 last = index +1;
116 if (index < first)
117 first = index;
118 }
119 return table;
120}
121
122
123static void
124cumulativedist(int *table, int limit, int *total)
125{
126 int accum=0;
127
128 while (--limit >= 0) {
129 accum += *table;
130 *table++ = accum;
131 }
132 *total = accum;
133}
134
135static short *
136inverttable(int *table, int inversesize, int tablesize, int cumulative)
137{
138 int i, inverseindex, inversevalue;
139 short *inverse;
140 double findex, fvalue;
141
142 inverse = (short *)malloc(inversesize*sizeof(short));
143 for (i=0; i < inversesize; ++i) {
144 inverse[i] = MINSHORT;
145 }
146 for (i=0; i < tablesize; ++i) {
147 findex = ((double)i/(double)DISTTABLEGRANULARITY) - DISTTABLEDOMAIN;
148 fvalue = (double)table[i]/(double)cumulative;
149 inverseindex = (int)rint(fvalue*inversesize);
150 inversevalue = (int)rint(findex*TABLEFACTOR);
151 if (inversevalue <= MINSHORT) inversevalue = MINSHORT+1;
152 if (inversevalue > MAXSHORT) inversevalue = MAXSHORT;
153 if (inverseindex >= inversesize) inverseindex = inversesize- 1;
154
155 inverse[inverseindex] = inversevalue;
156 }
157 return inverse;
158
159}
160
161
162static void
163interpolatetable(short *table, int limit)
164{
165 int i, j, last, lasti = -1;
166
167 last = MINSHORT;
168 for (i=0; i < limit; ++i) {
169 if (table[i] == MINSHORT) {
170 for (j=i; j < limit; ++j)
171 if (table[j] != MINSHORT)
172 break;
173 if (j < limit) {
174 table[i] = last + (i-lasti)*(table[j]-last)/(j-lasti);
175 } else {
176 table[i] = last + (i-lasti)*(MAXSHORT-last)/(limit-lasti);
177 }
178 } else {
179 last = table[i];
180 lasti = i;
181 }
182 }
183}
184
185static void
186printtable(const short *table, int limit)
187{
188 int i;
189
190 printf("# This is the distribution table for the experimental distribution.\n");
191
192 for (i=0 ; i < limit; ++i) {
193 printf("%d%c", table[i],
194 (i % 8) == 7 ? '\n' : ' ');
195 }
196}
197
198int
199main(int argc, char **argv)
200{
201 FILE *fp;
202 double *x;
203 double mu, sigma, rho;
204 int limit;
205 int *table;
206 short *inverse;
207 int total;
208
209 if (argc > 1) {
210 if (!(fp = fopen(argv[1], "r"))) {
211 perror(argv[1]);
212 exit(1);
213 }
214 } else {
215 fp = stdin;
216 }
217 x = readdoubles(fp, &limit);
218 if (limit <= 0) {
219 fprintf(stderr, "Nothing much read!\n");
220 exit(2);
221 }
222 arraystats(x, limit, &mu, &sigma, &rho);
223#ifdef DEBUG
224 fprintf(stderr, "%d values, mu %10.4f, sigma %10.4f, rho %10.4f\n",
225 limit, mu, sigma, rho);
226#endif
227
228 table = makedist(x, limit, mu, sigma);
229 free((void *) x);
230 cumulativedist(table, DISTTABLESIZE, &total);
231 inverse = inverttable(table, TABLESIZE, DISTTABLESIZE, total);
232 interpolatetable(inverse, TABLESIZE);
233 printtable(inverse, TABLESIZE);
234 return 0;
235}
236