Menu

[r6320]: / trunk / py4science / examples / pyrex / trailstats / ringbufnan.c  Maximize  Restore  History

Download this file

364 lines (314 with data), 7.9 kB

  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
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/*
Use a ring buffer to calculate running statistics of a data stream.
compile:
gcc -Wall -c -fPIC ringbufnan.c
2003/07/28 EF
*/
#include <stdlib.h>
#include <stdio.h> /* for debugging printf statements */
#include <math.h>
#include "ringbuf.h"
static double NaN = 0.0;
static void sort_ringbuf(ringbuf_t *rb_ptr);
static void resum_ringbuf(ringbuf_t *rb_ptr);
ringbuf_t *new_ringbuf(int N)
{
if (!isnan(NaN))
{
NaN = strtod("NaN", NULL); /* May change for Matlab. */
}
ringbuf_t *rb_ptr;
rb_ptr = calloc(1, sizeof(ringbuf_t));
rb_ptr->i_sorted = calloc(N, sizeof(int));
rb_ptr->data = calloc(N, sizeof(double));
rb_ptr->N_size = N;
zero_ringbuf(rb_ptr);
return rb_ptr;
}
void zero_ringbuf(ringbuf_t *rb_ptr)
{
rb_ptr->N_filled = 0;
rb_ptr->N_good = 0;
rb_ptr->N_added = 0;
rb_ptr->i_oldest = 0;
rb_ptr->i_next = 0;
rb_ptr->sum = 0.0;
rb_ptr->sumsq = 0.0;
}
void delete_ringbuf(ringbuf_t *rb_ptr)
{
free(rb_ptr->data);
free(rb_ptr->i_sorted);
free(rb_ptr);
}
int ringbuf_index(ringbuf_t *rb_ptr, int i)
/* i is a Python-style index; return the actual offset, or -1 for error */
{
/* printf("incoming index: %d", i);*/
if (i >= rb_ptr->N_filled) return -1;
if (i < -rb_ptr->N_filled) return -1;
if (i < 0) i += rb_ptr->i_next;
else i += rb_ptr->i_oldest;
i %= rb_ptr->N_size;
if (i < 0) i += rb_ptr->N_size;
/*printf("changed to offset: %d\n", i);*/
return i;
}
int ringbuf_slice_i(ringbuf_t *rb_ptr, int i)
/* For slices, out of range indices get clipped.*/
/* This function is not needed for the pyrex interface. */
{
/*printf("incoming index: %d", i);*/
if (i >= rb_ptr->N_filled) i = rb_ptr->N_filled;
if (i < -rb_ptr->N_filled) i = 0;
if (i < 0) i += rb_ptr->i_next;
else i += rb_ptr->i_oldest;
i %= rb_ptr->N_size;
if (i < 0) i += rb_ptr->N_size;
/*printf("changed to offset: %d\n", i);*/
return i;
}
double ringbuf_getitem(ringbuf_t *rb_ptr, int i)
{
i = ringbuf_index(rb_ptr, i);
if (i < 0) return 1e38;
return rb_ptr->data[i];
}
void resum_ringbuf(ringbuf_t *rb_ptr)
{
int i;
double d;
rb_ptr->sum = 0.0;
rb_ptr->sumsq = 0.0;
for (i = 0; i < rb_ptr->N_filled; i++)
{
d = rb_ptr->data[i];
if (!isnan(d))
{
rb_ptr->sum += d;
rb_ptr->sumsq += d*d;
}
}
}
void ringbuf_add(ringbuf_t *rb_ptr, double d)
{
double d_old;
int i, i_new, good_new, N;
N = rb_ptr->N_size; /* We need this many times. */
i_new = rb_ptr->i_next;
/* Save the old value; otherwise, it will be overwritten. */
d_old = rb_ptr->data[rb_ptr->i_oldest];
rb_ptr->data[i_new] = d;
good_new = !isnan(d);
#if 0
printf("new value: %lf good_new: %d\n", d, good_new);
printf("i_next: %d i_oldest: %d N_filled: %d N_good: %d\n",
rb_ptr->i_next, rb_ptr->i_oldest,
rb_ptr->N_filled, rb_ptr->N_good);
#endif
rb_ptr->i_next++;
rb_ptr->i_next %= N;
if (rb_ptr->N_filled == rb_ptr->N_size) /* already full */
{
if (!isnan(d_old))
{
rb_ptr->sum -= d_old;
rb_ptr->sumsq -= d_old * d_old;
/* Remove the i_oldest entry from i_sorted,
and slide the remaining entries down.
*/
for (i = 0; i < rb_ptr->N_good; i++)
{
if (rb_ptr->i_sorted[i] == rb_ptr->i_oldest)
break;
}
for ( ; i < rb_ptr->N_good - 1; i++)
{
rb_ptr->i_sorted[i] = rb_ptr->i_sorted[i+1];
}
rb_ptr->N_good--;
}
/* The new entry is temporarily put at the end of the array.
*/
if (good_new)
{
rb_ptr->i_sorted[rb_ptr->N_good] = i_new;
rb_ptr->N_good++;
}
rb_ptr->i_oldest++;
rb_ptr->i_oldest %= N;
}
else /* not full before adding this element */
{
if (good_new)
{
rb_ptr->i_sorted[rb_ptr->N_good] = i_new;
rb_ptr->N_good++;
}
rb_ptr->N_filled++;
}
if (good_new)
{
rb_ptr->sum += d;
rb_ptr->sumsq += d*d;
sort_ringbuf(rb_ptr);
}
/* To prevent accumulation of truncation error, we
recalculate the sums periodically.
*/
rb_ptr->N_added++;
if (rb_ptr->N_added % (rb_ptr->N_size + 10000) == 0)
{
resum_ringbuf(rb_ptr);
}
#if 0
printf("i_next: %d i_oldest: %d N_filled: %d N_good: %d\n",
rb_ptr->i_next, rb_ptr->i_oldest,
rb_ptr->N_filled, rb_ptr->N_good);
#endif
}
/* This is not a full sort--it assumes the list is
already sorted except for the last entry. It uses a single
pass of bubble sorting to put that entry in its place.
The code could be moved bodily into the function above.
*/
void sort_ringbuf(ringbuf_t *rb_ptr)
{
int i, i_hold;
int *ip;
double *dp;
ip = rb_ptr->i_sorted;
dp = rb_ptr->data;
for (i = rb_ptr->N_good - 1; i > 0; i--)
{
if (dp[ip[i]] < dp[ip[i-1]])
{
i_hold = ip[i];
ip[i] = ip[i-1];
ip[i-1] = i_hold;
}
else
{
break;
}
}
}
double ringbuf_min(ringbuf_t *rb_ptr)
{
return rb_ptr->data[rb_ptr->i_sorted[0]];
}
double ringbuf_max(ringbuf_t *rb_ptr)
{
int i_end;
i_end = rb_ptr->N_good - 1;
return rb_ptr->data[rb_ptr->i_sorted[i_end]];
}
double ringbuf_median(ringbuf_t *rb_ptr)
{
int i_mid, N;
N = rb_ptr->N_good;
if (N == 0) return NaN;
i_mid = N/2;
if (N % 2 == 1)
{
return rb_ptr->data[rb_ptr->i_sorted[i_mid]];
}
else
{
return 0.5 * (rb_ptr->data[rb_ptr->i_sorted[i_mid]]
+ rb_ptr->data[rb_ptr->i_sorted[i_mid - 1]]);
}
}
int ringbuf_N_good(ringbuf_t *rb_ptr)
{
return rb_ptr->N_good;
}
int ringbuf_N_filled(ringbuf_t *rb_ptr)
{
return rb_ptr->N_filled;
}
int ringbuf_N_added(ringbuf_t *rb_ptr)
{
return rb_ptr->N_added;
}
double ringbuf_mean(ringbuf_t *rb_ptr)
{
int N;
N = rb_ptr->N_good;
if (N > 0)
{
return rb_ptr->sum / N;
}
else
{
return NaN;
}
}
double ringbuf_sd(ringbuf_t *rb_ptr)
{
double m, s;
int N;
N = rb_ptr->N_good;
if (N == 0)
return NaN;
m = ringbuf_mean(rb_ptr);
s = rb_ptr->sumsq / N - m*m;
if (s > 0.0)
{
return sqrt(s);
}
else
{
return 0.0;
}
}
void c_runstats(int nrb, int nd, double *data, double *dmean, double *dstd,
double *dmin, double *dmax, double *dmed, int *ng)
{
int i, j;
ringbuf_t *rb_ptr;
rb_ptr = new_ringbuf(nrb);
for (j=0; j<nd; i++, j++)
{
ringbuf_add(rb_ptr, data[j]);
dmean[j] = ringbuf_mean(rb_ptr);
dstd[j] = ringbuf_sd(rb_ptr);
dmin[j] = ringbuf_min(rb_ptr);
dmax[j] = ringbuf_max(rb_ptr);
dmed[j] = ringbuf_median(rb_ptr);
ng[j] = rb_ptr->N_good;
}
delete_ringbuf(rb_ptr);
}
void c_runstats2(int nrb, int nd, int step, int ofs,
double *data, double *dmean, double *dstd,
double *dmin, double *dmax, double *dmed, int *ng)
{
int i, j;
int npad = (nrb - 1) / 2;
ringbuf_t *rb_ptr;
data += ofs;
dmean += ofs;
dstd += ofs;
dmin += ofs;
dmax += ofs;
dmed += ofs;
ng += ofs;
rb_ptr = new_ringbuf(nrb);
for (i = 0; i < npad; i++)
{
ringbuf_add(rb_ptr, data[i*step]);
}
for (j=0; j<nd; i++, j++)
{
if (i < nd) {ringbuf_add(rb_ptr, data[i*step]);}
else {ringbuf_add(rb_ptr, NaN);}
dmean[j*step] = ringbuf_mean(rb_ptr);
dstd[j*step] = ringbuf_sd(rb_ptr);
dmin[j*step] = ringbuf_min(rb_ptr);
dmax[j*step] = ringbuf_max(rb_ptr);
dmed[j*step] = ringbuf_median(rb_ptr);
ng[j*step] = rb_ptr->N_good;
}
delete_ringbuf(rb_ptr);
}
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.