-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLRbin.c
201 lines (170 loc) · 4.57 KB
/
LRbin.c
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
/*!
\file LRbin.c
\brief Set of LibRan binning functions
This set of LibRan functions will set-up or take-down the `LR_bin` object
and the bins for
counting values into bins based on the bin boundaries.
Each of the `LR_bin` objects is independent of any other object such as
the `LR_obj`.
Having such bins are useful for visualizing a random variates distribution.
Given the total number of samples is \e N, then the number of likely
samples falling within the bin will be
\f[
N \int_{x_i}^{x_{i+1}}f(x)dx = N \left[F(x_{i+1}) - F(x_i)\right]
\f]
where the bin interval is \f$ [x_i,x_{i+1}) \f$ and \f$ f(x) \f$
is the probability distribution function (PDF) and \f$ F(x) \f$
is the cumulative distribution function (CDF).
The bin object also tallies samples below and above the set of bins.
If you define \e n-1 boundaries then there are \e n bins.
The order the boundaries are set is not important. The method orders
the boundaries internally.
The following is some example code fragments for defining the bins, tallying
the samples, and viewing the results.
\code
#include <stdio.h>
#include "libran.h"
...
int nbin = 10;
LR_bin *b = LR_bin_new(nbin+2);
...
// set the boundaries
for (int i = 0; i <= nbin; i++) {
LR_bin_set(b, 2.0 + .1 * i);
}
...
// tally samples
for (int i = 0; i < 10000; i++) {
LR_bin_add(b, LRd_RAN(o));
}
...
// view results
fprint("-inf - %f : %f\n", b->bdrs[0], b->bins[0]);
for (int i = 1; i <= nbin; i++) {
fprint("%f - %f : %f\n", b->bdrs[i-1], b->bdrs[i], b->bins[i]);
}
fprint("%f - inf : %f\n", b->bdrs[nbin+1], b->bins[nbin+1]);
...
LR_bin_rm(&b);
\endcode
*/
/*
* Copyright 2019 R.K. Owen, Ph.D.
* License see lgpl.md (Gnu Lesser General Public License)
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <math.h> /* isnan() */
#include "libran.h"
/*!
@brief LR_bin_new(LR_data_type d, int n) - create new binning object
This routine creates a new `LR_bin` object and allocates the necessary
memory for the boundaries and tally bins. Must give at least the expected
number of bins or the number of boundaries plus one.
@param t data type
@param n number of bins
@return LR_bin object if successful, else NULL
*/
LR_bin *LR_bin_new(int n) {
LR_bin *ptr = (void *) NULL;
if (!(ptr = (LR_bin *) malloc(sizeof(LR_bin))))
return ptr;
ptr->n = n;
ptr->nn = 1; /* always start with one bin */
ptr->c = 0;
ptr->errno = 0;
if (!(ptr->bdrs = (double *) calloc(n, sizeof(double))))
goto bad0;
if (!(ptr->bins = (long *) calloc(n, sizeof(long))))
goto bad1;
return ptr;
bad1:
free((void *) ptr->bdrs);
bad0:
free((void *) ptr);
return (void *) NULL;
}
/*!
@brief LR_bin_rm(LR_bin **b) - remove binning object
Since the `LR_bin` object allocates memory this method needs to be
called to deallocate the memory to avoid memory leaks.
@param b LR_bin object address
@return 0 if successful, else non-zero if failed
*/
int LR_bin_rm(LR_bin **b) {
if (b && *b) {
free((void *) (*b)->bins);
free((void *) (*b)->bdrs);
free((void *) *b);
*b = (LR_bin *) NULL;
return LRerr_OK;
}
return LRerr_BinGeneric;
}
/*!
@brief LR_bin_set(LR_bin *b, double x) - add bin boundary
Include another bin boundary, which will be ordered internally.
However, it will not identify or flag repeated boundaries.
@param b LR_bin object
@param x bin boundary to add
@return 0 if successful, else non-zero if failed
*/
int LR_bin_set(LR_bin *b, double x) {
int i = 0;
double t;
if (b->n < b->nn + 1) {
/* too many values given */
return b->errno = LRerr_TooManyValues;
}
t = b->bdrs[0];
for (int i = 0, i1 = 1; i <= b->nn; i++,i1++) {
if (b->nn == i1) { /* got to top entry */
b->bdrs[i] = x;
b->nn++;
return LRerr_OK;
}
if (x > t) {
/* compare to next one, next round */
t = b->bdrs[i1];
} else {
/* insert here, but keep current */
t = b->bdrs[i];
b->bdrs[i] = x;
/* use current for comparison */
x = t;
t = b->bdrs[i1];
}
}
b->nn++;
return LRerr_OK;
}
/*!
@brief LR_bin_add(LR_bin *b, double x) - collect value to be binned.
This is *the* tallying routine, where the value \e x is compared to the
boundary values and the appropriate bin array element tally is incremented.
@param b LR_bin object
@param x value to count within the given bin.
@return 0 if successful, else non-zero if failed
*/
int LR_bin_add(LR_bin *b, double x) {
int i = 0;
if (isnan(x))
return b->errno = LRerr_InvalidInputValue;
while (i <= b->nn - 1) {
if (x < b->bdrs[i]
|| i == b->nn - 1) {
b->bins[i]++;
break;
}
i++;
}
if (i >= b->nn)
return b->errno = LRerr_InvalidRange;
b->c++;
return LRerr_OK;
}
#ifdef __cplusplus
}
#endif