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