1 /***************************************************************************
2 TEMPLATE:
3 void binCounts_<L|R>(...)
4
5 GENERATES:
6 void binCounts_L(double *x, int nx, double *bx, int nbins, int *count)
7 void binCounts_R(double *x, int nx, double *bx, int nbins, int *count)
8
9 Arguments:
10 The following macros ("arguments") should be defined for the
11 template to work as intended.
12 - BIN_BY: 'L' or 'R'
13
14 Copyright Henrik Bengtsson, 2012-2014
15 **************************************************************************/
16 #include <Rinternals.h>
17
18 #if BIN_BY == 'L' /* [u,v) */
19 #define METHOD_NAME binCounts_L
20 #define IS_PART_OF_FIRST_BIN(x, bx0) (x < bx0)
21 #define IS_PART_OF_NEXT_BIN(x, bx1) (x >= bx1)
22 #elif BIN_BY == 'R' /* (u,v] */
23 #define METHOD_NAME binCounts_R
24 #define IS_PART_OF_FIRST_BIN(x, bx0) (x <= bx0)
25 #define IS_PART_OF_NEXT_BIN(x, bx1) (x > bx1)
26 #endif
27
METHOD_NAME(double * x,R_xlen_t nx,double * bx,R_xlen_t nbins,int * count)28 void METHOD_NAME(double *x, R_xlen_t nx, double *bx, R_xlen_t nbins, int *count) {
29 R_xlen_t ii = 0, jj = 0, iStart = 0;
30 int n = 0;
31 int warn = 0;
32
33 // Count?
34 if (nbins > 0) {
35
36 // Skip to the first bin
37 while ((iStart < nx) && IS_PART_OF_FIRST_BIN(x[iStart], bx[0])) {
38 ++iStart;
39 }
40
41 // For each x...
42 for (ii = iStart; ii < nx; ++ii) {
43
44 // Skip to a new bin?
45 while (IS_PART_OF_NEXT_BIN(x[ii], bx[jj+1])) {
46 count[jj++] = n;
47
48 // No more bins?
49 if (jj >= nbins) {
50 ii = nx; // Cause outer for-loop to exit
51 break;
52 }
53
54 n = 0;
55 }
56
57 /* Although unlikely, with long vectors the count for a bin
58 can become greater than what is possible to represent by
59 an integer. Detect and warn about this. */
60 if (n == R_INT_MAX) {
61 warn = 1;
62 // No point in keep counting for this bin
63 break;
64 }
65
66 // Count
67 ++n;
68 }
69
70 // Update count of the last bin?
71 if (jj < nbins) {
72 count[jj] = n;
73
74 // Assign the remaining bins to zero counts
75 while (++jj < nbins) {
76 count[jj] = 0;
77 }
78 }
79
80 } // if (nbins > 0)
81
82 if (warn) {
83 warning("Integer overflow. Detected one or more bins with a count that is greater than what can be represented by the integer data type. Setting count to the maximum integer possible (.Machine$integer.max = %d). The bin mean is still correct.", R_INT_MAX);
84 }
85 }
86
87
88 /* Undo template macros */
89 #undef BIN_BY
90 #undef IS_PART_OF_FIRST_BIN
91 #undef IS_PART_OF_NEXT_BIN
92 #include "000.templates-types_undef.h"
93
94
95 /***************************************************************************
96 HISTORY:
97 2014-11-07 [HB]
98 o ROBUSTNESS: Added protection for integer overflow in bin counts.
99 2014-11-06 [HB]
100 o CLEANUP: Moving away from R data types in low-level C functions.
101 2013-10-08 [HB]
102 o Created template for binCounts_<L|R>() to create functions that
103 bin either by [u,v) or (u,v].
104 2013-05-10 [HB]
105 o SPEEDUP: binCounts() no longer tests in every iteration (=for every
106 data point) whether the last bin has been reached or not.
107 2012-10-10 [HB]
108 o BUG FIX: binCounts() would return random/garbage counts for bins
109 that were beyond the last data point.
110 o BUG FIX: In some cases binCounts() could try to go past the last bin.
111 2012-10-03 [HB]
112 o Created.
113 **************************************************************************/
114