carray 3.0.5 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +233 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_axis_dispatch.c +6 -0
  6. data/ext/ca_axis_group.c +1 -1
  7. data/ext/ca_categorical_iterator.c +7 -7
  8. data/ext/ca_kernel_iterator.c +116 -231
  9. data/ext/ca_kernel_iterator.h +410 -254
  10. data/ext/ca_obj_bincmp.c +9 -1
  11. data/ext/ca_obj_binop.c +10 -1
  12. data/ext/ca_obj_bitfield.c +2 -0
  13. data/ext/ca_obj_byte_swap.c +2 -0
  14. data/ext/ca_obj_face.c +2 -0
  15. data/ext/ca_obj_fake.c +3 -1
  16. data/ext/ca_obj_grid.c +167 -12
  17. data/ext/ca_obj_meld.c +69 -113
  18. data/ext/ca_obj_moncmp.c +9 -1
  19. data/ext/ca_obj_monop.c +40 -2
  20. data/ext/ca_obj_object.c +54 -20
  21. data/ext/ca_obj_reduce.c +15 -1
  22. data/ext/ca_obj_refer.c +65 -20
  23. data/ext/ca_obj_remap.c +69 -10
  24. data/ext/ca_obj_roll.c +1 -0
  25. data/ext/ca_obj_select.c +4 -1
  26. data/ext/ca_obj_select_axis.c +1 -0
  27. data/ext/ca_obj_shift.c +1 -0
  28. data/ext/ca_obj_stack.c +310 -111
  29. data/ext/ca_obj_stride.c +131 -45
  30. data/ext/ca_obj_string.c +18 -2
  31. data/ext/ca_obj_tile.c +1 -0
  32. data/ext/ca_obj_triop.c +9 -1
  33. data/ext/ca_obj_window.c +1 -0
  34. data/ext/ca_op_ipower.c +8 -8
  35. data/ext/caframe_csv_reader.c +1 -1
  36. data/ext/carray.h +2 -1
  37. data/ext/carray_access.c +27 -64
  38. data/ext/carray_address_basis.c +134 -0
  39. data/ext/carray_attribute.c +8 -0
  40. data/ext/carray_broadcast.c +3 -4
  41. data/ext/carray_build_flags.h +1 -1
  42. data/ext/carray_cast.c +8 -11
  43. data/ext/carray_conversion.c +9 -5
  44. data/ext/carray_core.c +811 -72
  45. data/ext/carray_element.c +13 -9
  46. data/ext/carray_histogram.c +25 -3
  47. data/ext/carray_internal.h +147 -12
  48. data/ext/carray_kernels_bincmp.c +2007 -3
  49. data/ext/carray_kernels_binop.c +25365 -5199
  50. data/ext/carray_kernels_init.c +8 -8
  51. data/ext/carray_kernels_monop.c +10696 -3678
  52. data/ext/carray_kernels_reduce_aggregate.c +4429 -702
  53. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  54. data/ext/carray_kernels_reduce_cumulative.c +1808 -248
  55. data/ext/carray_kernels_reduce_extreme.c +4508 -511
  56. data/ext/carray_kernels_reduce_variance.c +2284 -152
  57. data/ext/carray_kernels_scan.c +240 -240
  58. data/ext/carray_kernels_search.c +4211 -264
  59. data/ext/carray_kernels_sort.c +367 -450
  60. data/ext/carray_lazy.c +47 -0
  61. data/ext/carray_loop.c +1 -1
  62. data/ext/carray_mask.c +130 -139
  63. data/ext/carray_median_percentile.c +4 -4
  64. data/ext/carray_memory_view.c +13 -7
  65. data/ext/carray_operator.c +147 -44
  66. data/ext/carray_order.c +3 -2
  67. data/ext/carray_random.c +4 -1
  68. data/ext/carray_slab.c +97 -21
  69. data/ext/carray_sort.c +1 -1
  70. data/ext/carray_test.c +74 -19
  71. data/ext/carray_time_text.c +2 -2
  72. data/ext/extconf.rb +11 -0
  73. data/ext/mkkernel.rb +346 -94
  74. data/ext/ruby_carray.c +4 -1
  75. data/ext/version.h +4 -4
  76. data/lib/carray/attribute.rb +25 -1
  77. data/lib/carray/autoload_carray.rb +3 -3
  78. data/lib/carray/autoload_method_extension.rb +5 -3
  79. data/lib/carray/axis_group.rb +13 -7
  80. data/lib/carray/basics.rb +1 -1
  81. data/lib/carray/block_iterator.rb +17 -3
  82. data/lib/carray/categorical.rb +6 -8
  83. data/lib/carray/categorical_iterator.rb +2 -2
  84. data/lib/carray/complex.rb +2 -2
  85. data/lib/carray/conditional.rb +3 -2
  86. data/lib/carray/frame/column_verbs.rb +45 -14
  87. data/lib/carray/frame/convert.rb +19 -0
  88. data/lib/carray/frame/csv_parser.rb +32 -32
  89. data/lib/carray/frame/describe.rb +4 -2
  90. data/lib/carray/frame/frame.rb +399 -78
  91. data/lib/carray/frame/group.rb +679 -53
  92. data/lib/carray/frame/io.rb +209 -71
  93. data/lib/carray/frame/join.rb +146 -37
  94. data/lib/carray/frame/records.rb +3 -3
  95. data/lib/carray/frame/reshape.rb +89 -11
  96. data/lib/carray/frame/sort.rb +57 -9
  97. data/lib/carray/frame/verbs.rb +384 -49
  98. data/lib/carray/frame/windows.rb +44 -6
  99. data/lib/carray/inspect.rb +7 -2
  100. data/lib/carray/iterator.rb +32 -0
  101. data/lib/carray/lazy.rb +17 -8
  102. data/lib/carray/mask_gap_fill.rb +37 -17
  103. data/lib/carray/meld_reduce.rb +1 -1
  104. data/lib/carray/methods/choose.rb +3 -2
  105. data/lib/carray/methods/meshgrid.rb +3 -1
  106. data/lib/carray/runtime.rb +47 -8
  107. data/lib/carray/segment_iterator.rb +23 -8
  108. data/lib/carray/serialize.rb +34 -17
  109. data/lib/carray/stack.rb +18 -6
  110. data/lib/carray/time.rb +5 -0
  111. data/lib/carray/window_iterator.rb +16 -4
  112. data/yard-stubs/ca_obj_array.rb +26 -1
  113. data/yard-stubs/carray_cast.rb +8 -5
  114. data/yard-stubs/carray_conversion.rb +8 -2
  115. data/yard-stubs/carray_mask.rb +20 -1
  116. data/yard-stubs/carray_math.rb +31 -16
  117. data/yard-stubs/carray_memory_view.rb +7 -0
  118. data/yard-stubs/carray_test.rb +7 -4
  119. metadata +18 -4
@@ -47,14 +47,40 @@ static inline VALUE BOOL2VAL (boolean8_t x) { return x ? Qtrue : Qfalse; }
47
47
 
48
48
  #define __variancep_i8_P1EXPR(__x) ((double)(__x))
49
49
  #define __variancep_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
50
+ /* The walks can raise part way (a Ruby call per cell in the object
51
+ lane, an allocation in any lane). Their states live in the caller's
52
+ frame, and ca_iter_ensure finishes them however the body leaves. */
53
+ typedef struct {
54
+ ca_iter_state states[1];
55
+ VALUE self;
56
+ CArray *ca;
57
+ int8_t *slab_axes;
58
+ int8_t naxes;
59
+ int keep_axis;
60
+ ca_size_t min_count;
61
+ } variancep_ki_native_i8_frame;
62
+
50
63
  static VALUE
51
- variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
64
+ variancep_ki_native_i8_body (VALUE arg)
52
65
  {
66
+ variancep_ki_native_i8_frame *fr = (variancep_ki_native_i8_frame *) arg;
67
+ VALUE self = fr->self;
68
+ (void) self;
69
+ CArray *ca = fr->ca;
70
+ (void) ca;
71
+ int8_t *slab_axes = fr->slab_axes;
72
+ (void) slab_axes;
73
+ int8_t naxes = fr->naxes;
74
+ (void) naxes;
75
+ int keep_axis = fr->keep_axis;
76
+ (void) keep_axis;
77
+ ca_size_t min_count = fr->min_count;
78
+ (void) min_count;
79
+ #define st (fr->states[0])
53
80
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
54
81
  CArray *co;
55
82
  GetCArray(vout, co);
56
83
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
57
- ca_iter_state st;
58
84
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
59
85
  slab_axes, naxes, 0);
60
86
  if ( rc != CA_ITER_OK ) {
@@ -69,7 +95,7 @@ variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
69
95
  /* Pass 1: sum = Σx (+ masked_cnt) */
70
96
  double sum = 0.0;
71
97
  ca_size_t masked_cnt = 0;
72
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __variancep_i8_P1EXPR, masked_cnt);
98
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(int8_t, double, st, p, m, sum, 0.0, __variancep_i8_P1EXPR, masked_cnt);
73
99
  ca_size_t n_valid = st.slab_elements - masked_cnt;
74
100
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
75
101
  if ( __trigger ) {
@@ -84,7 +110,7 @@ variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
84
110
  /* Pass 2: M2 = Σ (x - mean)² */
85
111
  double M2 = 0.0;
86
112
  ca_size_t __unused_mc = 0;
87
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __variancep_i8_P2EXPR, __unused_mc);
113
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __variancep_i8_P2EXPR, __unused_mc);
88
114
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
89
115
  }
90
116
  }
@@ -98,20 +124,61 @@ variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
98
124
  return rb_float_new(op[0]);
99
125
  }
100
126
  return vout;
127
+ #undef st
101
128
  }
129
+
130
+ static VALUE
131
+ variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
132
+ {
133
+ variancep_ki_native_i8_frame fr;
134
+ fr.self = self;
135
+ fr.ca = ca;
136
+ fr.slab_axes = slab_axes;
137
+ fr.naxes = naxes;
138
+ fr.keep_axis = keep_axis;
139
+ fr.min_count = min_count;
140
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_i8_body, (VALUE) &fr);
141
+ }
142
+
102
143
  #undef __variancep_i8_P1EXPR
103
144
  #undef __variancep_i8_P2EXPR
104
145
 
105
146
  #define __variancep_u8_P1EXPR(__x) ((double)(__x))
106
147
  #define __variancep_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
148
+ /* The walks can raise part way (a Ruby call per cell in the object
149
+ lane, an allocation in any lane). Their states live in the caller's
150
+ frame, and ca_iter_ensure finishes them however the body leaves. */
151
+ typedef struct {
152
+ ca_iter_state states[1];
153
+ VALUE self;
154
+ CArray *ca;
155
+ int8_t *slab_axes;
156
+ int8_t naxes;
157
+ int keep_axis;
158
+ ca_size_t min_count;
159
+ } variancep_ki_native_u8_frame;
160
+
107
161
  static VALUE
108
- variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
162
+ variancep_ki_native_u8_body (VALUE arg)
109
163
  {
164
+ variancep_ki_native_u8_frame *fr = (variancep_ki_native_u8_frame *) arg;
165
+ VALUE self = fr->self;
166
+ (void) self;
167
+ CArray *ca = fr->ca;
168
+ (void) ca;
169
+ int8_t *slab_axes = fr->slab_axes;
170
+ (void) slab_axes;
171
+ int8_t naxes = fr->naxes;
172
+ (void) naxes;
173
+ int keep_axis = fr->keep_axis;
174
+ (void) keep_axis;
175
+ ca_size_t min_count = fr->min_count;
176
+ (void) min_count;
177
+ #define st (fr->states[0])
110
178
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
111
179
  CArray *co;
112
180
  GetCArray(vout, co);
113
181
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
114
- ca_iter_state st;
115
182
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
116
183
  slab_axes, naxes, 0);
117
184
  if ( rc != CA_ITER_OK ) {
@@ -126,7 +193,7 @@ variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
126
193
  /* Pass 1: sum = Σx (+ masked_cnt) */
127
194
  double sum = 0.0;
128
195
  ca_size_t masked_cnt = 0;
129
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __variancep_u8_P1EXPR, masked_cnt);
196
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(uint8_t, double, st, p, m, sum, 0.0, __variancep_u8_P1EXPR, masked_cnt);
130
197
  ca_size_t n_valid = st.slab_elements - masked_cnt;
131
198
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
132
199
  if ( __trigger ) {
@@ -141,7 +208,7 @@ variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
141
208
  /* Pass 2: M2 = Σ (x - mean)² */
142
209
  double M2 = 0.0;
143
210
  ca_size_t __unused_mc = 0;
144
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __variancep_u8_P2EXPR, __unused_mc);
211
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __variancep_u8_P2EXPR, __unused_mc);
145
212
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
146
213
  }
147
214
  }
@@ -155,20 +222,61 @@ variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
155
222
  return rb_float_new(op[0]);
156
223
  }
157
224
  return vout;
225
+ #undef st
226
+ }
227
+
228
+ static VALUE
229
+ variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
230
+ {
231
+ variancep_ki_native_u8_frame fr;
232
+ fr.self = self;
233
+ fr.ca = ca;
234
+ fr.slab_axes = slab_axes;
235
+ fr.naxes = naxes;
236
+ fr.keep_axis = keep_axis;
237
+ fr.min_count = min_count;
238
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_u8_body, (VALUE) &fr);
158
239
  }
240
+
159
241
  #undef __variancep_u8_P1EXPR
160
242
  #undef __variancep_u8_P2EXPR
161
243
 
162
244
  #define __variancep_i16_P1EXPR(__x) ((double)(__x))
163
245
  #define __variancep_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
246
+ /* The walks can raise part way (a Ruby call per cell in the object
247
+ lane, an allocation in any lane). Their states live in the caller's
248
+ frame, and ca_iter_ensure finishes them however the body leaves. */
249
+ typedef struct {
250
+ ca_iter_state states[1];
251
+ VALUE self;
252
+ CArray *ca;
253
+ int8_t *slab_axes;
254
+ int8_t naxes;
255
+ int keep_axis;
256
+ ca_size_t min_count;
257
+ } variancep_ki_native_i16_frame;
258
+
164
259
  static VALUE
165
- variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
260
+ variancep_ki_native_i16_body (VALUE arg)
166
261
  {
262
+ variancep_ki_native_i16_frame *fr = (variancep_ki_native_i16_frame *) arg;
263
+ VALUE self = fr->self;
264
+ (void) self;
265
+ CArray *ca = fr->ca;
266
+ (void) ca;
267
+ int8_t *slab_axes = fr->slab_axes;
268
+ (void) slab_axes;
269
+ int8_t naxes = fr->naxes;
270
+ (void) naxes;
271
+ int keep_axis = fr->keep_axis;
272
+ (void) keep_axis;
273
+ ca_size_t min_count = fr->min_count;
274
+ (void) min_count;
275
+ #define st (fr->states[0])
167
276
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
168
277
  CArray *co;
169
278
  GetCArray(vout, co);
170
279
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
171
- ca_iter_state st;
172
280
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
173
281
  slab_axes, naxes, 0);
174
282
  if ( rc != CA_ITER_OK ) {
@@ -183,7 +291,7 @@ variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
183
291
  /* Pass 1: sum = Σx (+ masked_cnt) */
184
292
  double sum = 0.0;
185
293
  ca_size_t masked_cnt = 0;
186
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __variancep_i16_P1EXPR, masked_cnt);
294
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __variancep_i16_P1EXPR, masked_cnt);
187
295
  ca_size_t n_valid = st.slab_elements - masked_cnt;
188
296
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
189
297
  if ( __trigger ) {
@@ -198,7 +306,7 @@ variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
198
306
  /* Pass 2: M2 = Σ (x - mean)² */
199
307
  double M2 = 0.0;
200
308
  ca_size_t __unused_mc = 0;
201
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, M2, 0.0, __variancep_i16_P2EXPR, __unused_mc);
309
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_int16_t, int64_t, st, p, m, M2, 0.0, mean, __variancep_i16_P2EXPR, __unused_mc);
202
310
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
203
311
  }
204
312
  }
@@ -212,20 +320,61 @@ variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
212
320
  return rb_float_new(op[0]);
213
321
  }
214
322
  return vout;
323
+ #undef st
324
+ }
325
+
326
+ static VALUE
327
+ variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
328
+ {
329
+ variancep_ki_native_i16_frame fr;
330
+ fr.self = self;
331
+ fr.ca = ca;
332
+ fr.slab_axes = slab_axes;
333
+ fr.naxes = naxes;
334
+ fr.keep_axis = keep_axis;
335
+ fr.min_count = min_count;
336
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_i16_body, (VALUE) &fr);
215
337
  }
338
+
216
339
  #undef __variancep_i16_P1EXPR
217
340
  #undef __variancep_i16_P2EXPR
218
341
 
219
342
  #define __variancep_u16_P1EXPR(__x) ((double)(__x))
220
343
  #define __variancep_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
344
+ /* The walks can raise part way (a Ruby call per cell in the object
345
+ lane, an allocation in any lane). Their states live in the caller's
346
+ frame, and ca_iter_ensure finishes them however the body leaves. */
347
+ typedef struct {
348
+ ca_iter_state states[1];
349
+ VALUE self;
350
+ CArray *ca;
351
+ int8_t *slab_axes;
352
+ int8_t naxes;
353
+ int keep_axis;
354
+ ca_size_t min_count;
355
+ } variancep_ki_native_u16_frame;
356
+
221
357
  static VALUE
222
- variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
358
+ variancep_ki_native_u16_body (VALUE arg)
223
359
  {
360
+ variancep_ki_native_u16_frame *fr = (variancep_ki_native_u16_frame *) arg;
361
+ VALUE self = fr->self;
362
+ (void) self;
363
+ CArray *ca = fr->ca;
364
+ (void) ca;
365
+ int8_t *slab_axes = fr->slab_axes;
366
+ (void) slab_axes;
367
+ int8_t naxes = fr->naxes;
368
+ (void) naxes;
369
+ int keep_axis = fr->keep_axis;
370
+ (void) keep_axis;
371
+ ca_size_t min_count = fr->min_count;
372
+ (void) min_count;
373
+ #define st (fr->states[0])
224
374
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
225
375
  CArray *co;
226
376
  GetCArray(vout, co);
227
377
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
228
- ca_iter_state st;
229
378
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
230
379
  slab_axes, naxes, 0);
231
380
  if ( rc != CA_ITER_OK ) {
@@ -240,7 +389,7 @@ variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
240
389
  /* Pass 1: sum = Σx (+ masked_cnt) */
241
390
  double sum = 0.0;
242
391
  ca_size_t masked_cnt = 0;
243
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __variancep_u16_P1EXPR, masked_cnt);
392
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __variancep_u16_P1EXPR, masked_cnt);
244
393
  ca_size_t n_valid = st.slab_elements - masked_cnt;
245
394
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
246
395
  if ( __trigger ) {
@@ -255,7 +404,7 @@ variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
255
404
  /* Pass 2: M2 = Σ (x - mean)² */
256
405
  double M2 = 0.0;
257
406
  ca_size_t __unused_mc = 0;
258
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, M2, 0.0, __variancep_u16_P2EXPR, __unused_mc);
407
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_uint16_t, int64_t, st, p, m, M2, 0.0, mean, __variancep_u16_P2EXPR, __unused_mc);
259
408
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
260
409
  }
261
410
  }
@@ -269,20 +418,61 @@ variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
269
418
  return rb_float_new(op[0]);
270
419
  }
271
420
  return vout;
421
+ #undef st
272
422
  }
423
+
424
+ static VALUE
425
+ variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
426
+ {
427
+ variancep_ki_native_u16_frame fr;
428
+ fr.self = self;
429
+ fr.ca = ca;
430
+ fr.slab_axes = slab_axes;
431
+ fr.naxes = naxes;
432
+ fr.keep_axis = keep_axis;
433
+ fr.min_count = min_count;
434
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_u16_body, (VALUE) &fr);
435
+ }
436
+
273
437
  #undef __variancep_u16_P1EXPR
274
438
  #undef __variancep_u16_P2EXPR
275
439
 
276
440
  #define __variancep_i32_P1EXPR(__x) ((double)(__x))
277
441
  #define __variancep_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
442
+ /* The walks can raise part way (a Ruby call per cell in the object
443
+ lane, an allocation in any lane). Their states live in the caller's
444
+ frame, and ca_iter_ensure finishes them however the body leaves. */
445
+ typedef struct {
446
+ ca_iter_state states[1];
447
+ VALUE self;
448
+ CArray *ca;
449
+ int8_t *slab_axes;
450
+ int8_t naxes;
451
+ int keep_axis;
452
+ ca_size_t min_count;
453
+ } variancep_ki_native_i32_frame;
454
+
278
455
  static VALUE
279
- variancep_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
456
+ variancep_ki_native_i32_body (VALUE arg)
280
457
  {
458
+ variancep_ki_native_i32_frame *fr = (variancep_ki_native_i32_frame *) arg;
459
+ VALUE self = fr->self;
460
+ (void) self;
461
+ CArray *ca = fr->ca;
462
+ (void) ca;
463
+ int8_t *slab_axes = fr->slab_axes;
464
+ (void) slab_axes;
465
+ int8_t naxes = fr->naxes;
466
+ (void) naxes;
467
+ int keep_axis = fr->keep_axis;
468
+ (void) keep_axis;
469
+ ca_size_t min_count = fr->min_count;
470
+ (void) min_count;
471
+ #define st (fr->states[0])
281
472
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
282
473
  CArray *co;
283
474
  GetCArray(vout, co);
284
475
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
285
- ca_iter_state st;
286
476
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
287
477
  slab_axes, naxes, 0);
288
478
  if ( rc != CA_ITER_OK ) {
@@ -326,20 +516,61 @@ variancep_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
326
516
  return rb_float_new(op[0]);
327
517
  }
328
518
  return vout;
519
+ #undef st
329
520
  }
521
+
522
+ static VALUE
523
+ variancep_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
524
+ {
525
+ variancep_ki_native_i32_frame fr;
526
+ fr.self = self;
527
+ fr.ca = ca;
528
+ fr.slab_axes = slab_axes;
529
+ fr.naxes = naxes;
530
+ fr.keep_axis = keep_axis;
531
+ fr.min_count = min_count;
532
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_i32_body, (VALUE) &fr);
533
+ }
534
+
330
535
  #undef __variancep_i32_P1EXPR
331
536
  #undef __variancep_i32_P2EXPR
332
537
 
333
538
  #define __variancep_u32_P1EXPR(__x) ((double)(__x))
334
539
  #define __variancep_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
540
+ /* The walks can raise part way (a Ruby call per cell in the object
541
+ lane, an allocation in any lane). Their states live in the caller's
542
+ frame, and ca_iter_ensure finishes them however the body leaves. */
543
+ typedef struct {
544
+ ca_iter_state states[1];
545
+ VALUE self;
546
+ CArray *ca;
547
+ int8_t *slab_axes;
548
+ int8_t naxes;
549
+ int keep_axis;
550
+ ca_size_t min_count;
551
+ } variancep_ki_native_u32_frame;
552
+
335
553
  static VALUE
336
- variancep_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
554
+ variancep_ki_native_u32_body (VALUE arg)
337
555
  {
556
+ variancep_ki_native_u32_frame *fr = (variancep_ki_native_u32_frame *) arg;
557
+ VALUE self = fr->self;
558
+ (void) self;
559
+ CArray *ca = fr->ca;
560
+ (void) ca;
561
+ int8_t *slab_axes = fr->slab_axes;
562
+ (void) slab_axes;
563
+ int8_t naxes = fr->naxes;
564
+ (void) naxes;
565
+ int keep_axis = fr->keep_axis;
566
+ (void) keep_axis;
567
+ ca_size_t min_count = fr->min_count;
568
+ (void) min_count;
569
+ #define st (fr->states[0])
338
570
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
339
571
  CArray *co;
340
572
  GetCArray(vout, co);
341
573
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
342
- ca_iter_state st;
343
574
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
344
575
  slab_axes, naxes, 0);
345
576
  if ( rc != CA_ITER_OK ) {
@@ -383,20 +614,61 @@ variancep_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
383
614
  return rb_float_new(op[0]);
384
615
  }
385
616
  return vout;
617
+ #undef st
618
+ }
619
+
620
+ static VALUE
621
+ variancep_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
622
+ {
623
+ variancep_ki_native_u32_frame fr;
624
+ fr.self = self;
625
+ fr.ca = ca;
626
+ fr.slab_axes = slab_axes;
627
+ fr.naxes = naxes;
628
+ fr.keep_axis = keep_axis;
629
+ fr.min_count = min_count;
630
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_u32_body, (VALUE) &fr);
386
631
  }
632
+
387
633
  #undef __variancep_u32_P1EXPR
388
634
  #undef __variancep_u32_P2EXPR
389
635
 
390
636
  #define __variancep_i64_P1EXPR(__x) ((double)(__x))
391
637
  #define __variancep_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
638
+ /* The walks can raise part way (a Ruby call per cell in the object
639
+ lane, an allocation in any lane). Their states live in the caller's
640
+ frame, and ca_iter_ensure finishes them however the body leaves. */
641
+ typedef struct {
642
+ ca_iter_state states[1];
643
+ VALUE self;
644
+ CArray *ca;
645
+ int8_t *slab_axes;
646
+ int8_t naxes;
647
+ int keep_axis;
648
+ ca_size_t min_count;
649
+ } variancep_ki_native_i64_frame;
650
+
392
651
  static VALUE
393
- variancep_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
652
+ variancep_ki_native_i64_body (VALUE arg)
394
653
  {
654
+ variancep_ki_native_i64_frame *fr = (variancep_ki_native_i64_frame *) arg;
655
+ VALUE self = fr->self;
656
+ (void) self;
657
+ CArray *ca = fr->ca;
658
+ (void) ca;
659
+ int8_t *slab_axes = fr->slab_axes;
660
+ (void) slab_axes;
661
+ int8_t naxes = fr->naxes;
662
+ (void) naxes;
663
+ int keep_axis = fr->keep_axis;
664
+ (void) keep_axis;
665
+ ca_size_t min_count = fr->min_count;
666
+ (void) min_count;
667
+ #define st (fr->states[0])
395
668
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
396
669
  CArray *co;
397
670
  GetCArray(vout, co);
398
671
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
399
- ca_iter_state st;
400
672
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
401
673
  slab_axes, naxes, 0);
402
674
  if ( rc != CA_ITER_OK ) {
@@ -440,20 +712,61 @@ variancep_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
440
712
  return rb_float_new(op[0]);
441
713
  }
442
714
  return vout;
715
+ #undef st
443
716
  }
717
+
718
+ static VALUE
719
+ variancep_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
720
+ {
721
+ variancep_ki_native_i64_frame fr;
722
+ fr.self = self;
723
+ fr.ca = ca;
724
+ fr.slab_axes = slab_axes;
725
+ fr.naxes = naxes;
726
+ fr.keep_axis = keep_axis;
727
+ fr.min_count = min_count;
728
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_i64_body, (VALUE) &fr);
729
+ }
730
+
444
731
  #undef __variancep_i64_P1EXPR
445
732
  #undef __variancep_i64_P2EXPR
446
733
 
447
734
  #define __variancep_u64_P1EXPR(__x) ((double)(__x))
448
735
  #define __variancep_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
736
+ /* The walks can raise part way (a Ruby call per cell in the object
737
+ lane, an allocation in any lane). Their states live in the caller's
738
+ frame, and ca_iter_ensure finishes them however the body leaves. */
739
+ typedef struct {
740
+ ca_iter_state states[1];
741
+ VALUE self;
742
+ CArray *ca;
743
+ int8_t *slab_axes;
744
+ int8_t naxes;
745
+ int keep_axis;
746
+ ca_size_t min_count;
747
+ } variancep_ki_native_u64_frame;
748
+
449
749
  static VALUE
450
- variancep_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
750
+ variancep_ki_native_u64_body (VALUE arg)
451
751
  {
752
+ variancep_ki_native_u64_frame *fr = (variancep_ki_native_u64_frame *) arg;
753
+ VALUE self = fr->self;
754
+ (void) self;
755
+ CArray *ca = fr->ca;
756
+ (void) ca;
757
+ int8_t *slab_axes = fr->slab_axes;
758
+ (void) slab_axes;
759
+ int8_t naxes = fr->naxes;
760
+ (void) naxes;
761
+ int keep_axis = fr->keep_axis;
762
+ (void) keep_axis;
763
+ ca_size_t min_count = fr->min_count;
764
+ (void) min_count;
765
+ #define st (fr->states[0])
452
766
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
453
767
  CArray *co;
454
768
  GetCArray(vout, co);
455
769
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
456
- ca_iter_state st;
457
770
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
458
771
  slab_axes, naxes, 0);
459
772
  if ( rc != CA_ITER_OK ) {
@@ -497,20 +810,61 @@ variancep_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
497
810
  return rb_float_new(op[0]);
498
811
  }
499
812
  return vout;
813
+ #undef st
500
814
  }
815
+
816
+ static VALUE
817
+ variancep_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
818
+ {
819
+ variancep_ki_native_u64_frame fr;
820
+ fr.self = self;
821
+ fr.ca = ca;
822
+ fr.slab_axes = slab_axes;
823
+ fr.naxes = naxes;
824
+ fr.keep_axis = keep_axis;
825
+ fr.min_count = min_count;
826
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_u64_body, (VALUE) &fr);
827
+ }
828
+
501
829
  #undef __variancep_u64_P1EXPR
502
830
  #undef __variancep_u64_P2EXPR
503
831
 
504
832
  #define __variancep_f32_P1EXPR(__x) ((double)(__x))
505
833
  #define __variancep_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
834
+ /* The walks can raise part way (a Ruby call per cell in the object
835
+ lane, an allocation in any lane). Their states live in the caller's
836
+ frame, and ca_iter_ensure finishes them however the body leaves. */
837
+ typedef struct {
838
+ ca_iter_state states[1];
839
+ VALUE self;
840
+ CArray *ca;
841
+ int8_t *slab_axes;
842
+ int8_t naxes;
843
+ int keep_axis;
844
+ ca_size_t min_count;
845
+ } variancep_ki_native_f32_frame;
846
+
506
847
  static VALUE
507
- variancep_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
848
+ variancep_ki_native_f32_body (VALUE arg)
508
849
  {
850
+ variancep_ki_native_f32_frame *fr = (variancep_ki_native_f32_frame *) arg;
851
+ VALUE self = fr->self;
852
+ (void) self;
853
+ CArray *ca = fr->ca;
854
+ (void) ca;
855
+ int8_t *slab_axes = fr->slab_axes;
856
+ (void) slab_axes;
857
+ int8_t naxes = fr->naxes;
858
+ (void) naxes;
859
+ int keep_axis = fr->keep_axis;
860
+ (void) keep_axis;
861
+ ca_size_t min_count = fr->min_count;
862
+ (void) min_count;
863
+ #define st (fr->states[0])
509
864
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
510
865
  CArray *co;
511
866
  GetCArray(vout, co);
512
867
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
513
- ca_iter_state st;
514
868
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
515
869
  slab_axes, naxes, 0);
516
870
  if ( rc != CA_ITER_OK ) {
@@ -554,20 +908,61 @@ variancep_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
554
908
  return rb_float_new(op[0]);
555
909
  }
556
910
  return vout;
911
+ #undef st
912
+ }
913
+
914
+ static VALUE
915
+ variancep_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
916
+ {
917
+ variancep_ki_native_f32_frame fr;
918
+ fr.self = self;
919
+ fr.ca = ca;
920
+ fr.slab_axes = slab_axes;
921
+ fr.naxes = naxes;
922
+ fr.keep_axis = keep_axis;
923
+ fr.min_count = min_count;
924
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_f32_body, (VALUE) &fr);
557
925
  }
926
+
558
927
  #undef __variancep_f32_P1EXPR
559
928
  #undef __variancep_f32_P2EXPR
560
929
 
561
930
  #define __variancep_f64_P1EXPR(__x) ((double)(__x))
562
931
  #define __variancep_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
932
+ /* The walks can raise part way (a Ruby call per cell in the object
933
+ lane, an allocation in any lane). Their states live in the caller's
934
+ frame, and ca_iter_ensure finishes them however the body leaves. */
935
+ typedef struct {
936
+ ca_iter_state states[1];
937
+ VALUE self;
938
+ CArray *ca;
939
+ int8_t *slab_axes;
940
+ int8_t naxes;
941
+ int keep_axis;
942
+ ca_size_t min_count;
943
+ } variancep_ki_native_f64_frame;
944
+
563
945
  static VALUE
564
- variancep_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
946
+ variancep_ki_native_f64_body (VALUE arg)
565
947
  {
948
+ variancep_ki_native_f64_frame *fr = (variancep_ki_native_f64_frame *) arg;
949
+ VALUE self = fr->self;
950
+ (void) self;
951
+ CArray *ca = fr->ca;
952
+ (void) ca;
953
+ int8_t *slab_axes = fr->slab_axes;
954
+ (void) slab_axes;
955
+ int8_t naxes = fr->naxes;
956
+ (void) naxes;
957
+ int keep_axis = fr->keep_axis;
958
+ (void) keep_axis;
959
+ ca_size_t min_count = fr->min_count;
960
+ (void) min_count;
961
+ #define st (fr->states[0])
566
962
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
567
963
  CArray *co;
568
964
  GetCArray(vout, co);
569
965
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
570
- ca_iter_state st;
571
966
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
572
967
  slab_axes, naxes, 0);
573
968
  if ( rc != CA_ITER_OK ) {
@@ -611,20 +1006,61 @@ variancep_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
611
1006
  return rb_float_new(op[0]);
612
1007
  }
613
1008
  return vout;
1009
+ #undef st
1010
+ }
1011
+
1012
+ static VALUE
1013
+ variancep_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1014
+ {
1015
+ variancep_ki_native_f64_frame fr;
1016
+ fr.self = self;
1017
+ fr.ca = ca;
1018
+ fr.slab_axes = slab_axes;
1019
+ fr.naxes = naxes;
1020
+ fr.keep_axis = keep_axis;
1021
+ fr.min_count = min_count;
1022
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_f64_body, (VALUE) &fr);
614
1023
  }
1024
+
615
1025
  #undef __variancep_f64_P1EXPR
616
1026
  #undef __variancep_f64_P2EXPR
617
1027
 
618
1028
  #define __variancep_cmplx64_P1EXPR(__x) (__x)
619
1029
  #define __variancep_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
1030
+ /* The walks can raise part way (a Ruby call per cell in the object
1031
+ lane, an allocation in any lane). Their states live in the caller's
1032
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1033
+ typedef struct {
1034
+ ca_iter_state states[1];
1035
+ VALUE self;
1036
+ CArray *ca;
1037
+ int8_t *slab_axes;
1038
+ int8_t naxes;
1039
+ int keep_axis;
1040
+ ca_size_t min_count;
1041
+ } variancep_ki_native_cmplx64_frame;
1042
+
620
1043
  static VALUE
621
- variancep_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1044
+ variancep_ki_native_cmplx64_body (VALUE arg)
622
1045
  {
1046
+ variancep_ki_native_cmplx64_frame *fr = (variancep_ki_native_cmplx64_frame *) arg;
1047
+ VALUE self = fr->self;
1048
+ (void) self;
1049
+ CArray *ca = fr->ca;
1050
+ (void) ca;
1051
+ int8_t *slab_axes = fr->slab_axes;
1052
+ (void) slab_axes;
1053
+ int8_t naxes = fr->naxes;
1054
+ (void) naxes;
1055
+ int keep_axis = fr->keep_axis;
1056
+ (void) keep_axis;
1057
+ ca_size_t min_count = fr->min_count;
1058
+ (void) min_count;
1059
+ #define st (fr->states[0])
623
1060
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
624
1061
  CArray *co;
625
1062
  GetCArray(vout, co);
626
1063
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
627
- ca_iter_state st;
628
1064
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
629
1065
  slab_axes, naxes, 0);
630
1066
  if ( rc != CA_ITER_OK ) {
@@ -668,20 +1104,61 @@ variancep_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t n
668
1104
  return rb_float_new(op[0]);
669
1105
  }
670
1106
  return vout;
1107
+ #undef st
671
1108
  }
1109
+
1110
+ static VALUE
1111
+ variancep_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1112
+ {
1113
+ variancep_ki_native_cmplx64_frame fr;
1114
+ fr.self = self;
1115
+ fr.ca = ca;
1116
+ fr.slab_axes = slab_axes;
1117
+ fr.naxes = naxes;
1118
+ fr.keep_axis = keep_axis;
1119
+ fr.min_count = min_count;
1120
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_cmplx64_body, (VALUE) &fr);
1121
+ }
1122
+
672
1123
  #undef __variancep_cmplx64_P1EXPR
673
1124
  #undef __variancep_cmplx64_P2EXPR
674
1125
 
675
1126
  #define __variancep_cmplx128_P1EXPR(__x) (__x)
676
1127
  #define __variancep_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
1128
+ /* The walks can raise part way (a Ruby call per cell in the object
1129
+ lane, an allocation in any lane). Their states live in the caller's
1130
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1131
+ typedef struct {
1132
+ ca_iter_state states[1];
1133
+ VALUE self;
1134
+ CArray *ca;
1135
+ int8_t *slab_axes;
1136
+ int8_t naxes;
1137
+ int keep_axis;
1138
+ ca_size_t min_count;
1139
+ } variancep_ki_native_cmplx128_frame;
1140
+
677
1141
  static VALUE
678
- variancep_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1142
+ variancep_ki_native_cmplx128_body (VALUE arg)
679
1143
  {
1144
+ variancep_ki_native_cmplx128_frame *fr = (variancep_ki_native_cmplx128_frame *) arg;
1145
+ VALUE self = fr->self;
1146
+ (void) self;
1147
+ CArray *ca = fr->ca;
1148
+ (void) ca;
1149
+ int8_t *slab_axes = fr->slab_axes;
1150
+ (void) slab_axes;
1151
+ int8_t naxes = fr->naxes;
1152
+ (void) naxes;
1153
+ int keep_axis = fr->keep_axis;
1154
+ (void) keep_axis;
1155
+ ca_size_t min_count = fr->min_count;
1156
+ (void) min_count;
1157
+ #define st (fr->states[0])
680
1158
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
681
1159
  CArray *co;
682
1160
  GetCArray(vout, co);
683
1161
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
684
- ca_iter_state st;
685
1162
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
686
1163
  slab_axes, naxes, 0);
687
1164
  if ( rc != CA_ITER_OK ) {
@@ -725,20 +1202,61 @@ variancep_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t
725
1202
  return rb_float_new(op[0]);
726
1203
  }
727
1204
  return vout;
1205
+ #undef st
1206
+ }
1207
+
1208
+ static VALUE
1209
+ variancep_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1210
+ {
1211
+ variancep_ki_native_cmplx128_frame fr;
1212
+ fr.self = self;
1213
+ fr.ca = ca;
1214
+ fr.slab_axes = slab_axes;
1215
+ fr.naxes = naxes;
1216
+ fr.keep_axis = keep_axis;
1217
+ fr.min_count = min_count;
1218
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_cmplx128_body, (VALUE) &fr);
728
1219
  }
1220
+
729
1221
  #undef __variancep_cmplx128_P1EXPR
730
1222
  #undef __variancep_cmplx128_P2EXPR
731
1223
 
732
1224
  #define __variancep_bool_P1EXPR(__x) ((double)(__x))
733
1225
  #define __variancep_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
1226
+ /* The walks can raise part way (a Ruby call per cell in the object
1227
+ lane, an allocation in any lane). Their states live in the caller's
1228
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1229
+ typedef struct {
1230
+ ca_iter_state states[1];
1231
+ VALUE self;
1232
+ CArray *ca;
1233
+ int8_t *slab_axes;
1234
+ int8_t naxes;
1235
+ int keep_axis;
1236
+ ca_size_t min_count;
1237
+ } variancep_ki_native_bool_frame;
1238
+
734
1239
  static VALUE
735
- variancep_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1240
+ variancep_ki_native_bool_body (VALUE arg)
736
1241
  {
1242
+ variancep_ki_native_bool_frame *fr = (variancep_ki_native_bool_frame *) arg;
1243
+ VALUE self = fr->self;
1244
+ (void) self;
1245
+ CArray *ca = fr->ca;
1246
+ (void) ca;
1247
+ int8_t *slab_axes = fr->slab_axes;
1248
+ (void) slab_axes;
1249
+ int8_t naxes = fr->naxes;
1250
+ (void) naxes;
1251
+ int keep_axis = fr->keep_axis;
1252
+ (void) keep_axis;
1253
+ ca_size_t min_count = fr->min_count;
1254
+ (void) min_count;
1255
+ #define st (fr->states[0])
737
1256
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
738
1257
  CArray *co;
739
1258
  GetCArray(vout, co);
740
1259
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
741
- ca_iter_state st;
742
1260
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
743
1261
  slab_axes, naxes, 0);
744
1262
  if ( rc != CA_ITER_OK ) {
@@ -782,13 +1300,28 @@ variancep_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxe
782
1300
  return rb_float_new(op[0]);
783
1301
  }
784
1302
  return vout;
1303
+ #undef st
1304
+ }
1305
+
1306
+ static VALUE
1307
+ variancep_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1308
+ {
1309
+ variancep_ki_native_bool_frame fr;
1310
+ fr.self = self;
1311
+ fr.ca = ca;
1312
+ fr.slab_axes = slab_axes;
1313
+ fr.naxes = naxes;
1314
+ fr.keep_axis = keep_axis;
1315
+ fr.min_count = min_count;
1316
+ return ca_iter_ensure(1, fr.states, variancep_ki_native_bool_body, (VALUE) &fr);
785
1317
  }
1318
+
786
1319
  #undef __variancep_bool_P1EXPR
787
1320
  #undef __variancep_bool_P2EXPR
788
1321
 
789
- /* The object lane calls Ruby for every cell, so a walk can raise part
790
- way. Its states live in the caller's frame, and ca_iter_ensure
791
- finishes them however the body leaves. */
1322
+ /* The walks can raise part way (a Ruby call per cell in the object
1323
+ lane, an allocation in any lane). Their states live in the caller's
1324
+ frame, and ca_iter_ensure finishes them however the body leaves. */
792
1325
  typedef struct {
793
1326
  ca_iter_state states[1];
794
1327
  VALUE self;
@@ -877,7 +1410,7 @@ variancep_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
877
1410
  fr.naxes = naxes;
878
1411
  fr.keep_axis = keep_axis;
879
1412
  fr.min_count = min_count;
880
- return ca_iter_ensure(1, fr.states, variancep_ki_native_object_body, (VALUE) &fr);
1413
+ return ca_iter_ensure_computing(ca, 1, fr.states, variancep_ki_native_object_body, (VALUE) &fr);
881
1414
  }
882
1415
 
883
1416
 
@@ -995,14 +1528,40 @@ rb_ca_variancep_ki (int argc, VALUE *argv, VALUE self)
995
1528
 
996
1529
  #define __variance_i8_P1EXPR(__x) ((double)(__x))
997
1530
  #define __variance_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
1531
+ /* The walks can raise part way (a Ruby call per cell in the object
1532
+ lane, an allocation in any lane). Their states live in the caller's
1533
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1534
+ typedef struct {
1535
+ ca_iter_state states[1];
1536
+ VALUE self;
1537
+ CArray *ca;
1538
+ int8_t *slab_axes;
1539
+ int8_t naxes;
1540
+ int keep_axis;
1541
+ ca_size_t min_count;
1542
+ } variance_ki_native_i8_frame;
1543
+
998
1544
  static VALUE
999
- variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1545
+ variance_ki_native_i8_body (VALUE arg)
1000
1546
  {
1547
+ variance_ki_native_i8_frame *fr = (variance_ki_native_i8_frame *) arg;
1548
+ VALUE self = fr->self;
1549
+ (void) self;
1550
+ CArray *ca = fr->ca;
1551
+ (void) ca;
1552
+ int8_t *slab_axes = fr->slab_axes;
1553
+ (void) slab_axes;
1554
+ int8_t naxes = fr->naxes;
1555
+ (void) naxes;
1556
+ int keep_axis = fr->keep_axis;
1557
+ (void) keep_axis;
1558
+ ca_size_t min_count = fr->min_count;
1559
+ (void) min_count;
1560
+ #define st (fr->states[0])
1001
1561
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1002
1562
  CArray *co;
1003
1563
  GetCArray(vout, co);
1004
1564
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1005
- ca_iter_state st;
1006
1565
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1007
1566
  slab_axes, naxes, 0);
1008
1567
  if ( rc != CA_ITER_OK ) {
@@ -1017,7 +1576,7 @@ variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1017
1576
  /* Pass 1: sum = Σx (+ masked_cnt) */
1018
1577
  double sum = 0.0;
1019
1578
  ca_size_t masked_cnt = 0;
1020
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __variance_i8_P1EXPR, masked_cnt);
1579
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(int8_t, double, st, p, m, sum, 0.0, __variance_i8_P1EXPR, masked_cnt);
1021
1580
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1022
1581
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1023
1582
  if ( __trigger ) {
@@ -1032,7 +1591,7 @@ variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1032
1591
  /* Pass 2: M2 = Σ (x - mean)² */
1033
1592
  double M2 = 0.0;
1034
1593
  ca_size_t __unused_mc = 0;
1035
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __variance_i8_P2EXPR, __unused_mc);
1594
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __variance_i8_P2EXPR, __unused_mc);
1036
1595
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1037
1596
  }
1038
1597
  }
@@ -1046,20 +1605,61 @@ variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1046
1605
  return rb_float_new(op[0]);
1047
1606
  }
1048
1607
  return vout;
1608
+ #undef st
1609
+ }
1610
+
1611
+ static VALUE
1612
+ variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1613
+ {
1614
+ variance_ki_native_i8_frame fr;
1615
+ fr.self = self;
1616
+ fr.ca = ca;
1617
+ fr.slab_axes = slab_axes;
1618
+ fr.naxes = naxes;
1619
+ fr.keep_axis = keep_axis;
1620
+ fr.min_count = min_count;
1621
+ return ca_iter_ensure(1, fr.states, variance_ki_native_i8_body, (VALUE) &fr);
1049
1622
  }
1623
+
1050
1624
  #undef __variance_i8_P1EXPR
1051
1625
  #undef __variance_i8_P2EXPR
1052
1626
 
1053
1627
  #define __variance_u8_P1EXPR(__x) ((double)(__x))
1054
1628
  #define __variance_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
1629
+ /* The walks can raise part way (a Ruby call per cell in the object
1630
+ lane, an allocation in any lane). Their states live in the caller's
1631
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1632
+ typedef struct {
1633
+ ca_iter_state states[1];
1634
+ VALUE self;
1635
+ CArray *ca;
1636
+ int8_t *slab_axes;
1637
+ int8_t naxes;
1638
+ int keep_axis;
1639
+ ca_size_t min_count;
1640
+ } variance_ki_native_u8_frame;
1641
+
1055
1642
  static VALUE
1056
- variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1643
+ variance_ki_native_u8_body (VALUE arg)
1057
1644
  {
1645
+ variance_ki_native_u8_frame *fr = (variance_ki_native_u8_frame *) arg;
1646
+ VALUE self = fr->self;
1647
+ (void) self;
1648
+ CArray *ca = fr->ca;
1649
+ (void) ca;
1650
+ int8_t *slab_axes = fr->slab_axes;
1651
+ (void) slab_axes;
1652
+ int8_t naxes = fr->naxes;
1653
+ (void) naxes;
1654
+ int keep_axis = fr->keep_axis;
1655
+ (void) keep_axis;
1656
+ ca_size_t min_count = fr->min_count;
1657
+ (void) min_count;
1658
+ #define st (fr->states[0])
1058
1659
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1059
1660
  CArray *co;
1060
1661
  GetCArray(vout, co);
1061
1662
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1062
- ca_iter_state st;
1063
1663
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1064
1664
  slab_axes, naxes, 0);
1065
1665
  if ( rc != CA_ITER_OK ) {
@@ -1074,7 +1674,7 @@ variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1074
1674
  /* Pass 1: sum = Σx (+ masked_cnt) */
1075
1675
  double sum = 0.0;
1076
1676
  ca_size_t masked_cnt = 0;
1077
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __variance_u8_P1EXPR, masked_cnt);
1677
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(uint8_t, double, st, p, m, sum, 0.0, __variance_u8_P1EXPR, masked_cnt);
1078
1678
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1079
1679
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1080
1680
  if ( __trigger ) {
@@ -1089,7 +1689,7 @@ variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1089
1689
  /* Pass 2: M2 = Σ (x - mean)² */
1090
1690
  double M2 = 0.0;
1091
1691
  ca_size_t __unused_mc = 0;
1092
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __variance_u8_P2EXPR, __unused_mc);
1692
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __variance_u8_P2EXPR, __unused_mc);
1093
1693
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1094
1694
  }
1095
1695
  }
@@ -1103,20 +1703,61 @@ variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1103
1703
  return rb_float_new(op[0]);
1104
1704
  }
1105
1705
  return vout;
1706
+ #undef st
1106
1707
  }
1708
+
1709
+ static VALUE
1710
+ variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1711
+ {
1712
+ variance_ki_native_u8_frame fr;
1713
+ fr.self = self;
1714
+ fr.ca = ca;
1715
+ fr.slab_axes = slab_axes;
1716
+ fr.naxes = naxes;
1717
+ fr.keep_axis = keep_axis;
1718
+ fr.min_count = min_count;
1719
+ return ca_iter_ensure(1, fr.states, variance_ki_native_u8_body, (VALUE) &fr);
1720
+ }
1721
+
1107
1722
  #undef __variance_u8_P1EXPR
1108
1723
  #undef __variance_u8_P2EXPR
1109
1724
 
1110
1725
  #define __variance_i16_P1EXPR(__x) ((double)(__x))
1111
1726
  #define __variance_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
1727
+ /* The walks can raise part way (a Ruby call per cell in the object
1728
+ lane, an allocation in any lane). Their states live in the caller's
1729
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1730
+ typedef struct {
1731
+ ca_iter_state states[1];
1732
+ VALUE self;
1733
+ CArray *ca;
1734
+ int8_t *slab_axes;
1735
+ int8_t naxes;
1736
+ int keep_axis;
1737
+ ca_size_t min_count;
1738
+ } variance_ki_native_i16_frame;
1739
+
1112
1740
  static VALUE
1113
- variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1741
+ variance_ki_native_i16_body (VALUE arg)
1114
1742
  {
1743
+ variance_ki_native_i16_frame *fr = (variance_ki_native_i16_frame *) arg;
1744
+ VALUE self = fr->self;
1745
+ (void) self;
1746
+ CArray *ca = fr->ca;
1747
+ (void) ca;
1748
+ int8_t *slab_axes = fr->slab_axes;
1749
+ (void) slab_axes;
1750
+ int8_t naxes = fr->naxes;
1751
+ (void) naxes;
1752
+ int keep_axis = fr->keep_axis;
1753
+ (void) keep_axis;
1754
+ ca_size_t min_count = fr->min_count;
1755
+ (void) min_count;
1756
+ #define st (fr->states[0])
1115
1757
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1116
1758
  CArray *co;
1117
1759
  GetCArray(vout, co);
1118
1760
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1119
- ca_iter_state st;
1120
1761
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1121
1762
  slab_axes, naxes, 0);
1122
1763
  if ( rc != CA_ITER_OK ) {
@@ -1131,7 +1772,7 @@ variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1131
1772
  /* Pass 1: sum = Σx (+ masked_cnt) */
1132
1773
  double sum = 0.0;
1133
1774
  ca_size_t masked_cnt = 0;
1134
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __variance_i16_P1EXPR, masked_cnt);
1775
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __variance_i16_P1EXPR, masked_cnt);
1135
1776
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1136
1777
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1137
1778
  if ( __trigger ) {
@@ -1146,7 +1787,7 @@ variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1146
1787
  /* Pass 2: M2 = Σ (x - mean)² */
1147
1788
  double M2 = 0.0;
1148
1789
  ca_size_t __unused_mc = 0;
1149
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, M2, 0.0, __variance_i16_P2EXPR, __unused_mc);
1790
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_int16_t, int64_t, st, p, m, M2, 0.0, mean, __variance_i16_P2EXPR, __unused_mc);
1150
1791
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1151
1792
  }
1152
1793
  }
@@ -1160,20 +1801,61 @@ variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1160
1801
  return rb_float_new(op[0]);
1161
1802
  }
1162
1803
  return vout;
1804
+ #undef st
1805
+ }
1806
+
1807
+ static VALUE
1808
+ variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1809
+ {
1810
+ variance_ki_native_i16_frame fr;
1811
+ fr.self = self;
1812
+ fr.ca = ca;
1813
+ fr.slab_axes = slab_axes;
1814
+ fr.naxes = naxes;
1815
+ fr.keep_axis = keep_axis;
1816
+ fr.min_count = min_count;
1817
+ return ca_iter_ensure(1, fr.states, variance_ki_native_i16_body, (VALUE) &fr);
1163
1818
  }
1819
+
1164
1820
  #undef __variance_i16_P1EXPR
1165
1821
  #undef __variance_i16_P2EXPR
1166
1822
 
1167
1823
  #define __variance_u16_P1EXPR(__x) ((double)(__x))
1168
1824
  #define __variance_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
1825
+ /* The walks can raise part way (a Ruby call per cell in the object
1826
+ lane, an allocation in any lane). Their states live in the caller's
1827
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1828
+ typedef struct {
1829
+ ca_iter_state states[1];
1830
+ VALUE self;
1831
+ CArray *ca;
1832
+ int8_t *slab_axes;
1833
+ int8_t naxes;
1834
+ int keep_axis;
1835
+ ca_size_t min_count;
1836
+ } variance_ki_native_u16_frame;
1837
+
1169
1838
  static VALUE
1170
- variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1839
+ variance_ki_native_u16_body (VALUE arg)
1171
1840
  {
1841
+ variance_ki_native_u16_frame *fr = (variance_ki_native_u16_frame *) arg;
1842
+ VALUE self = fr->self;
1843
+ (void) self;
1844
+ CArray *ca = fr->ca;
1845
+ (void) ca;
1846
+ int8_t *slab_axes = fr->slab_axes;
1847
+ (void) slab_axes;
1848
+ int8_t naxes = fr->naxes;
1849
+ (void) naxes;
1850
+ int keep_axis = fr->keep_axis;
1851
+ (void) keep_axis;
1852
+ ca_size_t min_count = fr->min_count;
1853
+ (void) min_count;
1854
+ #define st (fr->states[0])
1172
1855
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1173
1856
  CArray *co;
1174
1857
  GetCArray(vout, co);
1175
1858
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1176
- ca_iter_state st;
1177
1859
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1178
1860
  slab_axes, naxes, 0);
1179
1861
  if ( rc != CA_ITER_OK ) {
@@ -1188,7 +1870,7 @@ variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1188
1870
  /* Pass 1: sum = Σx (+ masked_cnt) */
1189
1871
  double sum = 0.0;
1190
1872
  ca_size_t masked_cnt = 0;
1191
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __variance_u16_P1EXPR, masked_cnt);
1873
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __variance_u16_P1EXPR, masked_cnt);
1192
1874
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1193
1875
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1194
1876
  if ( __trigger ) {
@@ -1203,7 +1885,7 @@ variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1203
1885
  /* Pass 2: M2 = Σ (x - mean)² */
1204
1886
  double M2 = 0.0;
1205
1887
  ca_size_t __unused_mc = 0;
1206
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, M2, 0.0, __variance_u16_P2EXPR, __unused_mc);
1888
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_uint16_t, int64_t, st, p, m, M2, 0.0, mean, __variance_u16_P2EXPR, __unused_mc);
1207
1889
  op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1208
1890
  }
1209
1891
  }
@@ -1217,20 +1899,61 @@ variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1217
1899
  return rb_float_new(op[0]);
1218
1900
  }
1219
1901
  return vout;
1902
+ #undef st
1903
+ }
1904
+
1905
+ static VALUE
1906
+ variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1907
+ {
1908
+ variance_ki_native_u16_frame fr;
1909
+ fr.self = self;
1910
+ fr.ca = ca;
1911
+ fr.slab_axes = slab_axes;
1912
+ fr.naxes = naxes;
1913
+ fr.keep_axis = keep_axis;
1914
+ fr.min_count = min_count;
1915
+ return ca_iter_ensure(1, fr.states, variance_ki_native_u16_body, (VALUE) &fr);
1220
1916
  }
1917
+
1221
1918
  #undef __variance_u16_P1EXPR
1222
1919
  #undef __variance_u16_P2EXPR
1223
1920
 
1224
1921
  #define __variance_i32_P1EXPR(__x) ((double)(__x))
1225
1922
  #define __variance_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
1923
+ /* The walks can raise part way (a Ruby call per cell in the object
1924
+ lane, an allocation in any lane). Their states live in the caller's
1925
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1926
+ typedef struct {
1927
+ ca_iter_state states[1];
1928
+ VALUE self;
1929
+ CArray *ca;
1930
+ int8_t *slab_axes;
1931
+ int8_t naxes;
1932
+ int keep_axis;
1933
+ ca_size_t min_count;
1934
+ } variance_ki_native_i32_frame;
1935
+
1226
1936
  static VALUE
1227
- variance_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
1937
+ variance_ki_native_i32_body (VALUE arg)
1228
1938
  {
1939
+ variance_ki_native_i32_frame *fr = (variance_ki_native_i32_frame *) arg;
1940
+ VALUE self = fr->self;
1941
+ (void) self;
1942
+ CArray *ca = fr->ca;
1943
+ (void) ca;
1944
+ int8_t *slab_axes = fr->slab_axes;
1945
+ (void) slab_axes;
1946
+ int8_t naxes = fr->naxes;
1947
+ (void) naxes;
1948
+ int keep_axis = fr->keep_axis;
1949
+ (void) keep_axis;
1950
+ ca_size_t min_count = fr->min_count;
1951
+ (void) min_count;
1952
+ #define st (fr->states[0])
1229
1953
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1230
1954
  CArray *co;
1231
1955
  GetCArray(vout, co);
1232
1956
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1233
- ca_iter_state st;
1234
1957
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1235
1958
  slab_axes, naxes, 0);
1236
1959
  if ( rc != CA_ITER_OK ) {
@@ -1274,20 +1997,61 @@ variance_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1274
1997
  return rb_float_new(op[0]);
1275
1998
  }
1276
1999
  return vout;
2000
+ #undef st
2001
+ }
2002
+
2003
+ static VALUE
2004
+ variance_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2005
+ {
2006
+ variance_ki_native_i32_frame fr;
2007
+ fr.self = self;
2008
+ fr.ca = ca;
2009
+ fr.slab_axes = slab_axes;
2010
+ fr.naxes = naxes;
2011
+ fr.keep_axis = keep_axis;
2012
+ fr.min_count = min_count;
2013
+ return ca_iter_ensure(1, fr.states, variance_ki_native_i32_body, (VALUE) &fr);
1277
2014
  }
2015
+
1278
2016
  #undef __variance_i32_P1EXPR
1279
2017
  #undef __variance_i32_P2EXPR
1280
2018
 
1281
2019
  #define __variance_u32_P1EXPR(__x) ((double)(__x))
1282
2020
  #define __variance_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
2021
+ /* The walks can raise part way (a Ruby call per cell in the object
2022
+ lane, an allocation in any lane). Their states live in the caller's
2023
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2024
+ typedef struct {
2025
+ ca_iter_state states[1];
2026
+ VALUE self;
2027
+ CArray *ca;
2028
+ int8_t *slab_axes;
2029
+ int8_t naxes;
2030
+ int keep_axis;
2031
+ ca_size_t min_count;
2032
+ } variance_ki_native_u32_frame;
2033
+
1283
2034
  static VALUE
1284
- variance_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2035
+ variance_ki_native_u32_body (VALUE arg)
1285
2036
  {
2037
+ variance_ki_native_u32_frame *fr = (variance_ki_native_u32_frame *) arg;
2038
+ VALUE self = fr->self;
2039
+ (void) self;
2040
+ CArray *ca = fr->ca;
2041
+ (void) ca;
2042
+ int8_t *slab_axes = fr->slab_axes;
2043
+ (void) slab_axes;
2044
+ int8_t naxes = fr->naxes;
2045
+ (void) naxes;
2046
+ int keep_axis = fr->keep_axis;
2047
+ (void) keep_axis;
2048
+ ca_size_t min_count = fr->min_count;
2049
+ (void) min_count;
2050
+ #define st (fr->states[0])
1286
2051
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1287
2052
  CArray *co;
1288
2053
  GetCArray(vout, co);
1289
2054
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1290
- ca_iter_state st;
1291
2055
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1292
2056
  slab_axes, naxes, 0);
1293
2057
  if ( rc != CA_ITER_OK ) {
@@ -1331,20 +2095,61 @@ variance_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1331
2095
  return rb_float_new(op[0]);
1332
2096
  }
1333
2097
  return vout;
2098
+ #undef st
1334
2099
  }
2100
+
2101
+ static VALUE
2102
+ variance_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2103
+ {
2104
+ variance_ki_native_u32_frame fr;
2105
+ fr.self = self;
2106
+ fr.ca = ca;
2107
+ fr.slab_axes = slab_axes;
2108
+ fr.naxes = naxes;
2109
+ fr.keep_axis = keep_axis;
2110
+ fr.min_count = min_count;
2111
+ return ca_iter_ensure(1, fr.states, variance_ki_native_u32_body, (VALUE) &fr);
2112
+ }
2113
+
1335
2114
  #undef __variance_u32_P1EXPR
1336
2115
  #undef __variance_u32_P2EXPR
1337
2116
 
1338
2117
  #define __variance_i64_P1EXPR(__x) ((double)(__x))
1339
2118
  #define __variance_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
2119
+ /* The walks can raise part way (a Ruby call per cell in the object
2120
+ lane, an allocation in any lane). Their states live in the caller's
2121
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2122
+ typedef struct {
2123
+ ca_iter_state states[1];
2124
+ VALUE self;
2125
+ CArray *ca;
2126
+ int8_t *slab_axes;
2127
+ int8_t naxes;
2128
+ int keep_axis;
2129
+ ca_size_t min_count;
2130
+ } variance_ki_native_i64_frame;
2131
+
1340
2132
  static VALUE
1341
- variance_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2133
+ variance_ki_native_i64_body (VALUE arg)
1342
2134
  {
2135
+ variance_ki_native_i64_frame *fr = (variance_ki_native_i64_frame *) arg;
2136
+ VALUE self = fr->self;
2137
+ (void) self;
2138
+ CArray *ca = fr->ca;
2139
+ (void) ca;
2140
+ int8_t *slab_axes = fr->slab_axes;
2141
+ (void) slab_axes;
2142
+ int8_t naxes = fr->naxes;
2143
+ (void) naxes;
2144
+ int keep_axis = fr->keep_axis;
2145
+ (void) keep_axis;
2146
+ ca_size_t min_count = fr->min_count;
2147
+ (void) min_count;
2148
+ #define st (fr->states[0])
1343
2149
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1344
2150
  CArray *co;
1345
2151
  GetCArray(vout, co);
1346
2152
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1347
- ca_iter_state st;
1348
2153
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1349
2154
  slab_axes, naxes, 0);
1350
2155
  if ( rc != CA_ITER_OK ) {
@@ -1388,20 +2193,61 @@ variance_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1388
2193
  return rb_float_new(op[0]);
1389
2194
  }
1390
2195
  return vout;
2196
+ #undef st
2197
+ }
2198
+
2199
+ static VALUE
2200
+ variance_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2201
+ {
2202
+ variance_ki_native_i64_frame fr;
2203
+ fr.self = self;
2204
+ fr.ca = ca;
2205
+ fr.slab_axes = slab_axes;
2206
+ fr.naxes = naxes;
2207
+ fr.keep_axis = keep_axis;
2208
+ fr.min_count = min_count;
2209
+ return ca_iter_ensure(1, fr.states, variance_ki_native_i64_body, (VALUE) &fr);
1391
2210
  }
2211
+
1392
2212
  #undef __variance_i64_P1EXPR
1393
2213
  #undef __variance_i64_P2EXPR
1394
2214
 
1395
2215
  #define __variance_u64_P1EXPR(__x) ((double)(__x))
1396
2216
  #define __variance_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
2217
+ /* The walks can raise part way (a Ruby call per cell in the object
2218
+ lane, an allocation in any lane). Their states live in the caller's
2219
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2220
+ typedef struct {
2221
+ ca_iter_state states[1];
2222
+ VALUE self;
2223
+ CArray *ca;
2224
+ int8_t *slab_axes;
2225
+ int8_t naxes;
2226
+ int keep_axis;
2227
+ ca_size_t min_count;
2228
+ } variance_ki_native_u64_frame;
2229
+
1397
2230
  static VALUE
1398
- variance_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2231
+ variance_ki_native_u64_body (VALUE arg)
1399
2232
  {
2233
+ variance_ki_native_u64_frame *fr = (variance_ki_native_u64_frame *) arg;
2234
+ VALUE self = fr->self;
2235
+ (void) self;
2236
+ CArray *ca = fr->ca;
2237
+ (void) ca;
2238
+ int8_t *slab_axes = fr->slab_axes;
2239
+ (void) slab_axes;
2240
+ int8_t naxes = fr->naxes;
2241
+ (void) naxes;
2242
+ int keep_axis = fr->keep_axis;
2243
+ (void) keep_axis;
2244
+ ca_size_t min_count = fr->min_count;
2245
+ (void) min_count;
2246
+ #define st (fr->states[0])
1400
2247
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1401
2248
  CArray *co;
1402
2249
  GetCArray(vout, co);
1403
2250
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1404
- ca_iter_state st;
1405
2251
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1406
2252
  slab_axes, naxes, 0);
1407
2253
  if ( rc != CA_ITER_OK ) {
@@ -1445,20 +2291,61 @@ variance_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1445
2291
  return rb_float_new(op[0]);
1446
2292
  }
1447
2293
  return vout;
2294
+ #undef st
2295
+ }
2296
+
2297
+ static VALUE
2298
+ variance_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2299
+ {
2300
+ variance_ki_native_u64_frame fr;
2301
+ fr.self = self;
2302
+ fr.ca = ca;
2303
+ fr.slab_axes = slab_axes;
2304
+ fr.naxes = naxes;
2305
+ fr.keep_axis = keep_axis;
2306
+ fr.min_count = min_count;
2307
+ return ca_iter_ensure(1, fr.states, variance_ki_native_u64_body, (VALUE) &fr);
1448
2308
  }
2309
+
1449
2310
  #undef __variance_u64_P1EXPR
1450
2311
  #undef __variance_u64_P2EXPR
1451
2312
 
1452
2313
  #define __variance_f32_P1EXPR(__x) ((double)(__x))
1453
2314
  #define __variance_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
2315
+ /* The walks can raise part way (a Ruby call per cell in the object
2316
+ lane, an allocation in any lane). Their states live in the caller's
2317
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2318
+ typedef struct {
2319
+ ca_iter_state states[1];
2320
+ VALUE self;
2321
+ CArray *ca;
2322
+ int8_t *slab_axes;
2323
+ int8_t naxes;
2324
+ int keep_axis;
2325
+ ca_size_t min_count;
2326
+ } variance_ki_native_f32_frame;
2327
+
1454
2328
  static VALUE
1455
- variance_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2329
+ variance_ki_native_f32_body (VALUE arg)
1456
2330
  {
2331
+ variance_ki_native_f32_frame *fr = (variance_ki_native_f32_frame *) arg;
2332
+ VALUE self = fr->self;
2333
+ (void) self;
2334
+ CArray *ca = fr->ca;
2335
+ (void) ca;
2336
+ int8_t *slab_axes = fr->slab_axes;
2337
+ (void) slab_axes;
2338
+ int8_t naxes = fr->naxes;
2339
+ (void) naxes;
2340
+ int keep_axis = fr->keep_axis;
2341
+ (void) keep_axis;
2342
+ ca_size_t min_count = fr->min_count;
2343
+ (void) min_count;
2344
+ #define st (fr->states[0])
1457
2345
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1458
2346
  CArray *co;
1459
2347
  GetCArray(vout, co);
1460
2348
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1461
- ca_iter_state st;
1462
2349
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1463
2350
  slab_axes, naxes, 0);
1464
2351
  if ( rc != CA_ITER_OK ) {
@@ -1502,20 +2389,61 @@ variance_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1502
2389
  return rb_float_new(op[0]);
1503
2390
  }
1504
2391
  return vout;
2392
+ #undef st
2393
+ }
2394
+
2395
+ static VALUE
2396
+ variance_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2397
+ {
2398
+ variance_ki_native_f32_frame fr;
2399
+ fr.self = self;
2400
+ fr.ca = ca;
2401
+ fr.slab_axes = slab_axes;
2402
+ fr.naxes = naxes;
2403
+ fr.keep_axis = keep_axis;
2404
+ fr.min_count = min_count;
2405
+ return ca_iter_ensure(1, fr.states, variance_ki_native_f32_body, (VALUE) &fr);
1505
2406
  }
2407
+
1506
2408
  #undef __variance_f32_P1EXPR
1507
2409
  #undef __variance_f32_P2EXPR
1508
2410
 
1509
2411
  #define __variance_f64_P1EXPR(__x) ((double)(__x))
1510
2412
  #define __variance_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
2413
+ /* The walks can raise part way (a Ruby call per cell in the object
2414
+ lane, an allocation in any lane). Their states live in the caller's
2415
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2416
+ typedef struct {
2417
+ ca_iter_state states[1];
2418
+ VALUE self;
2419
+ CArray *ca;
2420
+ int8_t *slab_axes;
2421
+ int8_t naxes;
2422
+ int keep_axis;
2423
+ ca_size_t min_count;
2424
+ } variance_ki_native_f64_frame;
2425
+
1511
2426
  static VALUE
1512
- variance_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2427
+ variance_ki_native_f64_body (VALUE arg)
1513
2428
  {
2429
+ variance_ki_native_f64_frame *fr = (variance_ki_native_f64_frame *) arg;
2430
+ VALUE self = fr->self;
2431
+ (void) self;
2432
+ CArray *ca = fr->ca;
2433
+ (void) ca;
2434
+ int8_t *slab_axes = fr->slab_axes;
2435
+ (void) slab_axes;
2436
+ int8_t naxes = fr->naxes;
2437
+ (void) naxes;
2438
+ int keep_axis = fr->keep_axis;
2439
+ (void) keep_axis;
2440
+ ca_size_t min_count = fr->min_count;
2441
+ (void) min_count;
2442
+ #define st (fr->states[0])
1514
2443
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1515
2444
  CArray *co;
1516
2445
  GetCArray(vout, co);
1517
2446
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1518
- ca_iter_state st;
1519
2447
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1520
2448
  slab_axes, naxes, 0);
1521
2449
  if ( rc != CA_ITER_OK ) {
@@ -1559,20 +2487,61 @@ variance_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1559
2487
  return rb_float_new(op[0]);
1560
2488
  }
1561
2489
  return vout;
2490
+ #undef st
1562
2491
  }
2492
+
2493
+ static VALUE
2494
+ variance_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2495
+ {
2496
+ variance_ki_native_f64_frame fr;
2497
+ fr.self = self;
2498
+ fr.ca = ca;
2499
+ fr.slab_axes = slab_axes;
2500
+ fr.naxes = naxes;
2501
+ fr.keep_axis = keep_axis;
2502
+ fr.min_count = min_count;
2503
+ return ca_iter_ensure(1, fr.states, variance_ki_native_f64_body, (VALUE) &fr);
2504
+ }
2505
+
1563
2506
  #undef __variance_f64_P1EXPR
1564
2507
  #undef __variance_f64_P2EXPR
1565
2508
 
1566
2509
  #define __variance_cmplx64_P1EXPR(__x) (__x)
1567
2510
  #define __variance_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
2511
+ /* The walks can raise part way (a Ruby call per cell in the object
2512
+ lane, an allocation in any lane). Their states live in the caller's
2513
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2514
+ typedef struct {
2515
+ ca_iter_state states[1];
2516
+ VALUE self;
2517
+ CArray *ca;
2518
+ int8_t *slab_axes;
2519
+ int8_t naxes;
2520
+ int keep_axis;
2521
+ ca_size_t min_count;
2522
+ } variance_ki_native_cmplx64_frame;
2523
+
1568
2524
  static VALUE
1569
- variance_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2525
+ variance_ki_native_cmplx64_body (VALUE arg)
1570
2526
  {
2527
+ variance_ki_native_cmplx64_frame *fr = (variance_ki_native_cmplx64_frame *) arg;
2528
+ VALUE self = fr->self;
2529
+ (void) self;
2530
+ CArray *ca = fr->ca;
2531
+ (void) ca;
2532
+ int8_t *slab_axes = fr->slab_axes;
2533
+ (void) slab_axes;
2534
+ int8_t naxes = fr->naxes;
2535
+ (void) naxes;
2536
+ int keep_axis = fr->keep_axis;
2537
+ (void) keep_axis;
2538
+ ca_size_t min_count = fr->min_count;
2539
+ (void) min_count;
2540
+ #define st (fr->states[0])
1571
2541
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1572
2542
  CArray *co;
1573
2543
  GetCArray(vout, co);
1574
2544
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1575
- ca_iter_state st;
1576
2545
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1577
2546
  slab_axes, naxes, 0);
1578
2547
  if ( rc != CA_ITER_OK ) {
@@ -1616,20 +2585,61 @@ variance_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
1616
2585
  return rb_float_new(op[0]);
1617
2586
  }
1618
2587
  return vout;
2588
+ #undef st
2589
+ }
2590
+
2591
+ static VALUE
2592
+ variance_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2593
+ {
2594
+ variance_ki_native_cmplx64_frame fr;
2595
+ fr.self = self;
2596
+ fr.ca = ca;
2597
+ fr.slab_axes = slab_axes;
2598
+ fr.naxes = naxes;
2599
+ fr.keep_axis = keep_axis;
2600
+ fr.min_count = min_count;
2601
+ return ca_iter_ensure(1, fr.states, variance_ki_native_cmplx64_body, (VALUE) &fr);
1619
2602
  }
2603
+
1620
2604
  #undef __variance_cmplx64_P1EXPR
1621
2605
  #undef __variance_cmplx64_P2EXPR
1622
2606
 
1623
2607
  #define __variance_cmplx128_P1EXPR(__x) (__x)
1624
2608
  #define __variance_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
2609
+ /* The walks can raise part way (a Ruby call per cell in the object
2610
+ lane, an allocation in any lane). Their states live in the caller's
2611
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2612
+ typedef struct {
2613
+ ca_iter_state states[1];
2614
+ VALUE self;
2615
+ CArray *ca;
2616
+ int8_t *slab_axes;
2617
+ int8_t naxes;
2618
+ int keep_axis;
2619
+ ca_size_t min_count;
2620
+ } variance_ki_native_cmplx128_frame;
2621
+
1625
2622
  static VALUE
1626
- variance_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2623
+ variance_ki_native_cmplx128_body (VALUE arg)
1627
2624
  {
2625
+ variance_ki_native_cmplx128_frame *fr = (variance_ki_native_cmplx128_frame *) arg;
2626
+ VALUE self = fr->self;
2627
+ (void) self;
2628
+ CArray *ca = fr->ca;
2629
+ (void) ca;
2630
+ int8_t *slab_axes = fr->slab_axes;
2631
+ (void) slab_axes;
2632
+ int8_t naxes = fr->naxes;
2633
+ (void) naxes;
2634
+ int keep_axis = fr->keep_axis;
2635
+ (void) keep_axis;
2636
+ ca_size_t min_count = fr->min_count;
2637
+ (void) min_count;
2638
+ #define st (fr->states[0])
1628
2639
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1629
2640
  CArray *co;
1630
2641
  GetCArray(vout, co);
1631
2642
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1632
- ca_iter_state st;
1633
2643
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1634
2644
  slab_axes, naxes, 0);
1635
2645
  if ( rc != CA_ITER_OK ) {
@@ -1673,20 +2683,61 @@ variance_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t n
1673
2683
  return rb_float_new(op[0]);
1674
2684
  }
1675
2685
  return vout;
2686
+ #undef st
2687
+ }
2688
+
2689
+ static VALUE
2690
+ variance_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2691
+ {
2692
+ variance_ki_native_cmplx128_frame fr;
2693
+ fr.self = self;
2694
+ fr.ca = ca;
2695
+ fr.slab_axes = slab_axes;
2696
+ fr.naxes = naxes;
2697
+ fr.keep_axis = keep_axis;
2698
+ fr.min_count = min_count;
2699
+ return ca_iter_ensure(1, fr.states, variance_ki_native_cmplx128_body, (VALUE) &fr);
1676
2700
  }
2701
+
1677
2702
  #undef __variance_cmplx128_P1EXPR
1678
2703
  #undef __variance_cmplx128_P2EXPR
1679
2704
 
1680
2705
  #define __variance_bool_P1EXPR(__x) ((double)(__x))
1681
2706
  #define __variance_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
2707
+ /* The walks can raise part way (a Ruby call per cell in the object
2708
+ lane, an allocation in any lane). Their states live in the caller's
2709
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2710
+ typedef struct {
2711
+ ca_iter_state states[1];
2712
+ VALUE self;
2713
+ CArray *ca;
2714
+ int8_t *slab_axes;
2715
+ int8_t naxes;
2716
+ int keep_axis;
2717
+ ca_size_t min_count;
2718
+ } variance_ki_native_bool_frame;
2719
+
1682
2720
  static VALUE
1683
- variance_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2721
+ variance_ki_native_bool_body (VALUE arg)
1684
2722
  {
2723
+ variance_ki_native_bool_frame *fr = (variance_ki_native_bool_frame *) arg;
2724
+ VALUE self = fr->self;
2725
+ (void) self;
2726
+ CArray *ca = fr->ca;
2727
+ (void) ca;
2728
+ int8_t *slab_axes = fr->slab_axes;
2729
+ (void) slab_axes;
2730
+ int8_t naxes = fr->naxes;
2731
+ (void) naxes;
2732
+ int keep_axis = fr->keep_axis;
2733
+ (void) keep_axis;
2734
+ ca_size_t min_count = fr->min_count;
2735
+ (void) min_count;
2736
+ #define st (fr->states[0])
1685
2737
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1686
2738
  CArray *co;
1687
2739
  GetCArray(vout, co);
1688
2740
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1689
- ca_iter_state st;
1690
2741
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1691
2742
  slab_axes, naxes, 0);
1692
2743
  if ( rc != CA_ITER_OK ) {
@@ -1730,13 +2781,28 @@ variance_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
1730
2781
  return rb_float_new(op[0]);
1731
2782
  }
1732
2783
  return vout;
2784
+ #undef st
2785
+ }
2786
+
2787
+ static VALUE
2788
+ variance_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
2789
+ {
2790
+ variance_ki_native_bool_frame fr;
2791
+ fr.self = self;
2792
+ fr.ca = ca;
2793
+ fr.slab_axes = slab_axes;
2794
+ fr.naxes = naxes;
2795
+ fr.keep_axis = keep_axis;
2796
+ fr.min_count = min_count;
2797
+ return ca_iter_ensure(1, fr.states, variance_ki_native_bool_body, (VALUE) &fr);
1733
2798
  }
2799
+
1734
2800
  #undef __variance_bool_P1EXPR
1735
2801
  #undef __variance_bool_P2EXPR
1736
2802
 
1737
- /* The object lane calls Ruby for every cell, so a walk can raise part
1738
- way. Its states live in the caller's frame, and ca_iter_ensure
1739
- finishes them however the body leaves. */
2803
+ /* The walks can raise part way (a Ruby call per cell in the object
2804
+ lane, an allocation in any lane). Their states live in the caller's
2805
+ frame, and ca_iter_ensure finishes them however the body leaves. */
1740
2806
  typedef struct {
1741
2807
  ca_iter_state states[1];
1742
2808
  VALUE self;
@@ -1825,7 +2891,7 @@ variance_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
1825
2891
  fr.naxes = naxes;
1826
2892
  fr.keep_axis = keep_axis;
1827
2893
  fr.min_count = min_count;
1828
- return ca_iter_ensure(1, fr.states, variance_ki_native_object_body, (VALUE) &fr);
2894
+ return ca_iter_ensure_computing(ca, 1, fr.states, variance_ki_native_object_body, (VALUE) &fr);
1829
2895
  }
1830
2896
 
1831
2897
 
@@ -1943,14 +3009,40 @@ rb_ca_variance_ki (int argc, VALUE *argv, VALUE self)
1943
3009
 
1944
3010
  #define __stddevp_i8_P1EXPR(__x) ((double)(__x))
1945
3011
  #define __stddevp_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3012
+ /* The walks can raise part way (a Ruby call per cell in the object
3013
+ lane, an allocation in any lane). Their states live in the caller's
3014
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3015
+ typedef struct {
3016
+ ca_iter_state states[1];
3017
+ VALUE self;
3018
+ CArray *ca;
3019
+ int8_t *slab_axes;
3020
+ int8_t naxes;
3021
+ int keep_axis;
3022
+ ca_size_t min_count;
3023
+ } stddevp_ki_native_i8_frame;
3024
+
1946
3025
  static VALUE
1947
- stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3026
+ stddevp_ki_native_i8_body (VALUE arg)
1948
3027
  {
3028
+ stddevp_ki_native_i8_frame *fr = (stddevp_ki_native_i8_frame *) arg;
3029
+ VALUE self = fr->self;
3030
+ (void) self;
3031
+ CArray *ca = fr->ca;
3032
+ (void) ca;
3033
+ int8_t *slab_axes = fr->slab_axes;
3034
+ (void) slab_axes;
3035
+ int8_t naxes = fr->naxes;
3036
+ (void) naxes;
3037
+ int keep_axis = fr->keep_axis;
3038
+ (void) keep_axis;
3039
+ ca_size_t min_count = fr->min_count;
3040
+ (void) min_count;
3041
+ #define st (fr->states[0])
1949
3042
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
1950
3043
  CArray *co;
1951
3044
  GetCArray(vout, co);
1952
3045
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
1953
- ca_iter_state st;
1954
3046
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
1955
3047
  slab_axes, naxes, 0);
1956
3048
  if ( rc != CA_ITER_OK ) {
@@ -1965,7 +3057,7 @@ stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
1965
3057
  /* Pass 1: sum = Σx (+ masked_cnt) */
1966
3058
  double sum = 0.0;
1967
3059
  ca_size_t masked_cnt = 0;
1968
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __stddevp_i8_P1EXPR, masked_cnt);
3060
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(int8_t, double, st, p, m, sum, 0.0, __stddevp_i8_P1EXPR, masked_cnt);
1969
3061
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1970
3062
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
1971
3063
  if ( __trigger ) {
@@ -1980,7 +3072,7 @@ stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
1980
3072
  /* Pass 2: M2 = Σ (x - mean)² */
1981
3073
  double M2 = 0.0;
1982
3074
  ca_size_t __unused_mc = 0;
1983
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __stddevp_i8_P2EXPR, __unused_mc);
3075
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __stddevp_i8_P2EXPR, __unused_mc);
1984
3076
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
1985
3077
  }
1986
3078
  }
@@ -1994,20 +3086,61 @@ stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
1994
3086
  return rb_float_new(op[0]);
1995
3087
  }
1996
3088
  return vout;
3089
+ #undef st
1997
3090
  }
3091
+
3092
+ static VALUE
3093
+ stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3094
+ {
3095
+ stddevp_ki_native_i8_frame fr;
3096
+ fr.self = self;
3097
+ fr.ca = ca;
3098
+ fr.slab_axes = slab_axes;
3099
+ fr.naxes = naxes;
3100
+ fr.keep_axis = keep_axis;
3101
+ fr.min_count = min_count;
3102
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_i8_body, (VALUE) &fr);
3103
+ }
3104
+
1998
3105
  #undef __stddevp_i8_P1EXPR
1999
3106
  #undef __stddevp_i8_P2EXPR
2000
3107
 
2001
3108
  #define __stddevp_u8_P1EXPR(__x) ((double)(__x))
2002
3109
  #define __stddevp_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3110
+ /* The walks can raise part way (a Ruby call per cell in the object
3111
+ lane, an allocation in any lane). Their states live in the caller's
3112
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3113
+ typedef struct {
3114
+ ca_iter_state states[1];
3115
+ VALUE self;
3116
+ CArray *ca;
3117
+ int8_t *slab_axes;
3118
+ int8_t naxes;
3119
+ int keep_axis;
3120
+ ca_size_t min_count;
3121
+ } stddevp_ki_native_u8_frame;
3122
+
2003
3123
  static VALUE
2004
- stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3124
+ stddevp_ki_native_u8_body (VALUE arg)
2005
3125
  {
3126
+ stddevp_ki_native_u8_frame *fr = (stddevp_ki_native_u8_frame *) arg;
3127
+ VALUE self = fr->self;
3128
+ (void) self;
3129
+ CArray *ca = fr->ca;
3130
+ (void) ca;
3131
+ int8_t *slab_axes = fr->slab_axes;
3132
+ (void) slab_axes;
3133
+ int8_t naxes = fr->naxes;
3134
+ (void) naxes;
3135
+ int keep_axis = fr->keep_axis;
3136
+ (void) keep_axis;
3137
+ ca_size_t min_count = fr->min_count;
3138
+ (void) min_count;
3139
+ #define st (fr->states[0])
2006
3140
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2007
3141
  CArray *co;
2008
3142
  GetCArray(vout, co);
2009
3143
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2010
- ca_iter_state st;
2011
3144
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2012
3145
  slab_axes, naxes, 0);
2013
3146
  if ( rc != CA_ITER_OK ) {
@@ -2022,7 +3155,7 @@ stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
2022
3155
  /* Pass 1: sum = Σx (+ masked_cnt) */
2023
3156
  double sum = 0.0;
2024
3157
  ca_size_t masked_cnt = 0;
2025
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __stddevp_u8_P1EXPR, masked_cnt);
3158
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(uint8_t, double, st, p, m, sum, 0.0, __stddevp_u8_P1EXPR, masked_cnt);
2026
3159
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2027
3160
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2028
3161
  if ( __trigger ) {
@@ -2037,7 +3170,7 @@ stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
2037
3170
  /* Pass 2: M2 = Σ (x - mean)² */
2038
3171
  double M2 = 0.0;
2039
3172
  ca_size_t __unused_mc = 0;
2040
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __stddevp_u8_P2EXPR, __unused_mc);
3173
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __stddevp_u8_P2EXPR, __unused_mc);
2041
3174
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2042
3175
  }
2043
3176
  }
@@ -2051,20 +3184,61 @@ stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
2051
3184
  return rb_float_new(op[0]);
2052
3185
  }
2053
3186
  return vout;
3187
+ #undef st
3188
+ }
3189
+
3190
+ static VALUE
3191
+ stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3192
+ {
3193
+ stddevp_ki_native_u8_frame fr;
3194
+ fr.self = self;
3195
+ fr.ca = ca;
3196
+ fr.slab_axes = slab_axes;
3197
+ fr.naxes = naxes;
3198
+ fr.keep_axis = keep_axis;
3199
+ fr.min_count = min_count;
3200
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_u8_body, (VALUE) &fr);
2054
3201
  }
3202
+
2055
3203
  #undef __stddevp_u8_P1EXPR
2056
3204
  #undef __stddevp_u8_P2EXPR
2057
3205
 
2058
3206
  #define __stddevp_i16_P1EXPR(__x) ((double)(__x))
2059
3207
  #define __stddevp_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3208
+ /* The walks can raise part way (a Ruby call per cell in the object
3209
+ lane, an allocation in any lane). Their states live in the caller's
3210
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3211
+ typedef struct {
3212
+ ca_iter_state states[1];
3213
+ VALUE self;
3214
+ CArray *ca;
3215
+ int8_t *slab_axes;
3216
+ int8_t naxes;
3217
+ int keep_axis;
3218
+ ca_size_t min_count;
3219
+ } stddevp_ki_native_i16_frame;
3220
+
2060
3221
  static VALUE
2061
- stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3222
+ stddevp_ki_native_i16_body (VALUE arg)
2062
3223
  {
3224
+ stddevp_ki_native_i16_frame *fr = (stddevp_ki_native_i16_frame *) arg;
3225
+ VALUE self = fr->self;
3226
+ (void) self;
3227
+ CArray *ca = fr->ca;
3228
+ (void) ca;
3229
+ int8_t *slab_axes = fr->slab_axes;
3230
+ (void) slab_axes;
3231
+ int8_t naxes = fr->naxes;
3232
+ (void) naxes;
3233
+ int keep_axis = fr->keep_axis;
3234
+ (void) keep_axis;
3235
+ ca_size_t min_count = fr->min_count;
3236
+ (void) min_count;
3237
+ #define st (fr->states[0])
2063
3238
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2064
3239
  CArray *co;
2065
3240
  GetCArray(vout, co);
2066
3241
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2067
- ca_iter_state st;
2068
3242
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2069
3243
  slab_axes, naxes, 0);
2070
3244
  if ( rc != CA_ITER_OK ) {
@@ -2079,7 +3253,7 @@ stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2079
3253
  /* Pass 1: sum = Σx (+ masked_cnt) */
2080
3254
  double sum = 0.0;
2081
3255
  ca_size_t masked_cnt = 0;
2082
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __stddevp_i16_P1EXPR, masked_cnt);
3256
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __stddevp_i16_P1EXPR, masked_cnt);
2083
3257
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2084
3258
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2085
3259
  if ( __trigger ) {
@@ -2094,7 +3268,7 @@ stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2094
3268
  /* Pass 2: M2 = Σ (x - mean)² */
2095
3269
  double M2 = 0.0;
2096
3270
  ca_size_t __unused_mc = 0;
2097
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, M2, 0.0, __stddevp_i16_P2EXPR, __unused_mc);
3271
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_int16_t, int64_t, st, p, m, M2, 0.0, mean, __stddevp_i16_P2EXPR, __unused_mc);
2098
3272
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2099
3273
  }
2100
3274
  }
@@ -2108,20 +3282,61 @@ stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2108
3282
  return rb_float_new(op[0]);
2109
3283
  }
2110
3284
  return vout;
3285
+ #undef st
3286
+ }
3287
+
3288
+ static VALUE
3289
+ stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3290
+ {
3291
+ stddevp_ki_native_i16_frame fr;
3292
+ fr.self = self;
3293
+ fr.ca = ca;
3294
+ fr.slab_axes = slab_axes;
3295
+ fr.naxes = naxes;
3296
+ fr.keep_axis = keep_axis;
3297
+ fr.min_count = min_count;
3298
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_i16_body, (VALUE) &fr);
2111
3299
  }
3300
+
2112
3301
  #undef __stddevp_i16_P1EXPR
2113
3302
  #undef __stddevp_i16_P2EXPR
2114
3303
 
2115
3304
  #define __stddevp_u16_P1EXPR(__x) ((double)(__x))
2116
3305
  #define __stddevp_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3306
+ /* The walks can raise part way (a Ruby call per cell in the object
3307
+ lane, an allocation in any lane). Their states live in the caller's
3308
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3309
+ typedef struct {
3310
+ ca_iter_state states[1];
3311
+ VALUE self;
3312
+ CArray *ca;
3313
+ int8_t *slab_axes;
3314
+ int8_t naxes;
3315
+ int keep_axis;
3316
+ ca_size_t min_count;
3317
+ } stddevp_ki_native_u16_frame;
3318
+
2117
3319
  static VALUE
2118
- stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3320
+ stddevp_ki_native_u16_body (VALUE arg)
2119
3321
  {
3322
+ stddevp_ki_native_u16_frame *fr = (stddevp_ki_native_u16_frame *) arg;
3323
+ VALUE self = fr->self;
3324
+ (void) self;
3325
+ CArray *ca = fr->ca;
3326
+ (void) ca;
3327
+ int8_t *slab_axes = fr->slab_axes;
3328
+ (void) slab_axes;
3329
+ int8_t naxes = fr->naxes;
3330
+ (void) naxes;
3331
+ int keep_axis = fr->keep_axis;
3332
+ (void) keep_axis;
3333
+ ca_size_t min_count = fr->min_count;
3334
+ (void) min_count;
3335
+ #define st (fr->states[0])
2120
3336
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2121
3337
  CArray *co;
2122
3338
  GetCArray(vout, co);
2123
3339
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2124
- ca_iter_state st;
2125
3340
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2126
3341
  slab_axes, naxes, 0);
2127
3342
  if ( rc != CA_ITER_OK ) {
@@ -2136,7 +3351,7 @@ stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2136
3351
  /* Pass 1: sum = Σx (+ masked_cnt) */
2137
3352
  double sum = 0.0;
2138
3353
  ca_size_t masked_cnt = 0;
2139
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __stddevp_u16_P1EXPR, masked_cnt);
3354
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __stddevp_u16_P1EXPR, masked_cnt);
2140
3355
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2141
3356
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2142
3357
  if ( __trigger ) {
@@ -2151,7 +3366,7 @@ stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2151
3366
  /* Pass 2: M2 = Σ (x - mean)² */
2152
3367
  double M2 = 0.0;
2153
3368
  ca_size_t __unused_mc = 0;
2154
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, M2, 0.0, __stddevp_u16_P2EXPR, __unused_mc);
3369
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_uint16_t, int64_t, st, p, m, M2, 0.0, mean, __stddevp_u16_P2EXPR, __unused_mc);
2155
3370
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2156
3371
  }
2157
3372
  }
@@ -2165,20 +3380,61 @@ stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2165
3380
  return rb_float_new(op[0]);
2166
3381
  }
2167
3382
  return vout;
3383
+ #undef st
3384
+ }
3385
+
3386
+ static VALUE
3387
+ stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3388
+ {
3389
+ stddevp_ki_native_u16_frame fr;
3390
+ fr.self = self;
3391
+ fr.ca = ca;
3392
+ fr.slab_axes = slab_axes;
3393
+ fr.naxes = naxes;
3394
+ fr.keep_axis = keep_axis;
3395
+ fr.min_count = min_count;
3396
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_u16_body, (VALUE) &fr);
2168
3397
  }
3398
+
2169
3399
  #undef __stddevp_u16_P1EXPR
2170
3400
  #undef __stddevp_u16_P2EXPR
2171
3401
 
2172
3402
  #define __stddevp_i32_P1EXPR(__x) ((double)(__x))
2173
3403
  #define __stddevp_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3404
+ /* The walks can raise part way (a Ruby call per cell in the object
3405
+ lane, an allocation in any lane). Their states live in the caller's
3406
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3407
+ typedef struct {
3408
+ ca_iter_state states[1];
3409
+ VALUE self;
3410
+ CArray *ca;
3411
+ int8_t *slab_axes;
3412
+ int8_t naxes;
3413
+ int keep_axis;
3414
+ ca_size_t min_count;
3415
+ } stddevp_ki_native_i32_frame;
3416
+
2174
3417
  static VALUE
2175
- stddevp_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3418
+ stddevp_ki_native_i32_body (VALUE arg)
2176
3419
  {
3420
+ stddevp_ki_native_i32_frame *fr = (stddevp_ki_native_i32_frame *) arg;
3421
+ VALUE self = fr->self;
3422
+ (void) self;
3423
+ CArray *ca = fr->ca;
3424
+ (void) ca;
3425
+ int8_t *slab_axes = fr->slab_axes;
3426
+ (void) slab_axes;
3427
+ int8_t naxes = fr->naxes;
3428
+ (void) naxes;
3429
+ int keep_axis = fr->keep_axis;
3430
+ (void) keep_axis;
3431
+ ca_size_t min_count = fr->min_count;
3432
+ (void) min_count;
3433
+ #define st (fr->states[0])
2177
3434
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2178
3435
  CArray *co;
2179
3436
  GetCArray(vout, co);
2180
3437
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2181
- ca_iter_state st;
2182
3438
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2183
3439
  slab_axes, naxes, 0);
2184
3440
  if ( rc != CA_ITER_OK ) {
@@ -2222,20 +3478,61 @@ stddevp_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2222
3478
  return rb_float_new(op[0]);
2223
3479
  }
2224
3480
  return vout;
3481
+ #undef st
2225
3482
  }
3483
+
3484
+ static VALUE
3485
+ stddevp_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3486
+ {
3487
+ stddevp_ki_native_i32_frame fr;
3488
+ fr.self = self;
3489
+ fr.ca = ca;
3490
+ fr.slab_axes = slab_axes;
3491
+ fr.naxes = naxes;
3492
+ fr.keep_axis = keep_axis;
3493
+ fr.min_count = min_count;
3494
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_i32_body, (VALUE) &fr);
3495
+ }
3496
+
2226
3497
  #undef __stddevp_i32_P1EXPR
2227
3498
  #undef __stddevp_i32_P2EXPR
2228
3499
 
2229
3500
  #define __stddevp_u32_P1EXPR(__x) ((double)(__x))
2230
3501
  #define __stddevp_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3502
+ /* The walks can raise part way (a Ruby call per cell in the object
3503
+ lane, an allocation in any lane). Their states live in the caller's
3504
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3505
+ typedef struct {
3506
+ ca_iter_state states[1];
3507
+ VALUE self;
3508
+ CArray *ca;
3509
+ int8_t *slab_axes;
3510
+ int8_t naxes;
3511
+ int keep_axis;
3512
+ ca_size_t min_count;
3513
+ } stddevp_ki_native_u32_frame;
3514
+
2231
3515
  static VALUE
2232
- stddevp_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3516
+ stddevp_ki_native_u32_body (VALUE arg)
2233
3517
  {
3518
+ stddevp_ki_native_u32_frame *fr = (stddevp_ki_native_u32_frame *) arg;
3519
+ VALUE self = fr->self;
3520
+ (void) self;
3521
+ CArray *ca = fr->ca;
3522
+ (void) ca;
3523
+ int8_t *slab_axes = fr->slab_axes;
3524
+ (void) slab_axes;
3525
+ int8_t naxes = fr->naxes;
3526
+ (void) naxes;
3527
+ int keep_axis = fr->keep_axis;
3528
+ (void) keep_axis;
3529
+ ca_size_t min_count = fr->min_count;
3530
+ (void) min_count;
3531
+ #define st (fr->states[0])
2234
3532
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2235
3533
  CArray *co;
2236
3534
  GetCArray(vout, co);
2237
3535
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2238
- ca_iter_state st;
2239
3536
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2240
3537
  slab_axes, naxes, 0);
2241
3538
  if ( rc != CA_ITER_OK ) {
@@ -2279,20 +3576,61 @@ stddevp_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2279
3576
  return rb_float_new(op[0]);
2280
3577
  }
2281
3578
  return vout;
3579
+ #undef st
3580
+ }
3581
+
3582
+ static VALUE
3583
+ stddevp_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3584
+ {
3585
+ stddevp_ki_native_u32_frame fr;
3586
+ fr.self = self;
3587
+ fr.ca = ca;
3588
+ fr.slab_axes = slab_axes;
3589
+ fr.naxes = naxes;
3590
+ fr.keep_axis = keep_axis;
3591
+ fr.min_count = min_count;
3592
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_u32_body, (VALUE) &fr);
2282
3593
  }
3594
+
2283
3595
  #undef __stddevp_u32_P1EXPR
2284
3596
  #undef __stddevp_u32_P2EXPR
2285
3597
 
2286
3598
  #define __stddevp_i64_P1EXPR(__x) ((double)(__x))
2287
3599
  #define __stddevp_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3600
+ /* The walks can raise part way (a Ruby call per cell in the object
3601
+ lane, an allocation in any lane). Their states live in the caller's
3602
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3603
+ typedef struct {
3604
+ ca_iter_state states[1];
3605
+ VALUE self;
3606
+ CArray *ca;
3607
+ int8_t *slab_axes;
3608
+ int8_t naxes;
3609
+ int keep_axis;
3610
+ ca_size_t min_count;
3611
+ } stddevp_ki_native_i64_frame;
3612
+
2288
3613
  static VALUE
2289
- stddevp_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3614
+ stddevp_ki_native_i64_body (VALUE arg)
2290
3615
  {
3616
+ stddevp_ki_native_i64_frame *fr = (stddevp_ki_native_i64_frame *) arg;
3617
+ VALUE self = fr->self;
3618
+ (void) self;
3619
+ CArray *ca = fr->ca;
3620
+ (void) ca;
3621
+ int8_t *slab_axes = fr->slab_axes;
3622
+ (void) slab_axes;
3623
+ int8_t naxes = fr->naxes;
3624
+ (void) naxes;
3625
+ int keep_axis = fr->keep_axis;
3626
+ (void) keep_axis;
3627
+ ca_size_t min_count = fr->min_count;
3628
+ (void) min_count;
3629
+ #define st (fr->states[0])
2291
3630
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2292
3631
  CArray *co;
2293
3632
  GetCArray(vout, co);
2294
3633
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2295
- ca_iter_state st;
2296
3634
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2297
3635
  slab_axes, naxes, 0);
2298
3636
  if ( rc != CA_ITER_OK ) {
@@ -2336,20 +3674,61 @@ stddevp_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2336
3674
  return rb_float_new(op[0]);
2337
3675
  }
2338
3676
  return vout;
3677
+ #undef st
3678
+ }
3679
+
3680
+ static VALUE
3681
+ stddevp_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3682
+ {
3683
+ stddevp_ki_native_i64_frame fr;
3684
+ fr.self = self;
3685
+ fr.ca = ca;
3686
+ fr.slab_axes = slab_axes;
3687
+ fr.naxes = naxes;
3688
+ fr.keep_axis = keep_axis;
3689
+ fr.min_count = min_count;
3690
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_i64_body, (VALUE) &fr);
2339
3691
  }
3692
+
2340
3693
  #undef __stddevp_i64_P1EXPR
2341
3694
  #undef __stddevp_i64_P2EXPR
2342
3695
 
2343
3696
  #define __stddevp_u64_P1EXPR(__x) ((double)(__x))
2344
3697
  #define __stddevp_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3698
+ /* The walks can raise part way (a Ruby call per cell in the object
3699
+ lane, an allocation in any lane). Their states live in the caller's
3700
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3701
+ typedef struct {
3702
+ ca_iter_state states[1];
3703
+ VALUE self;
3704
+ CArray *ca;
3705
+ int8_t *slab_axes;
3706
+ int8_t naxes;
3707
+ int keep_axis;
3708
+ ca_size_t min_count;
3709
+ } stddevp_ki_native_u64_frame;
3710
+
2345
3711
  static VALUE
2346
- stddevp_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3712
+ stddevp_ki_native_u64_body (VALUE arg)
2347
3713
  {
3714
+ stddevp_ki_native_u64_frame *fr = (stddevp_ki_native_u64_frame *) arg;
3715
+ VALUE self = fr->self;
3716
+ (void) self;
3717
+ CArray *ca = fr->ca;
3718
+ (void) ca;
3719
+ int8_t *slab_axes = fr->slab_axes;
3720
+ (void) slab_axes;
3721
+ int8_t naxes = fr->naxes;
3722
+ (void) naxes;
3723
+ int keep_axis = fr->keep_axis;
3724
+ (void) keep_axis;
3725
+ ca_size_t min_count = fr->min_count;
3726
+ (void) min_count;
3727
+ #define st (fr->states[0])
2348
3728
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2349
3729
  CArray *co;
2350
3730
  GetCArray(vout, co);
2351
3731
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2352
- ca_iter_state st;
2353
3732
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2354
3733
  slab_axes, naxes, 0);
2355
3734
  if ( rc != CA_ITER_OK ) {
@@ -2393,20 +3772,61 @@ stddevp_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2393
3772
  return rb_float_new(op[0]);
2394
3773
  }
2395
3774
  return vout;
3775
+ #undef st
3776
+ }
3777
+
3778
+ static VALUE
3779
+ stddevp_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3780
+ {
3781
+ stddevp_ki_native_u64_frame fr;
3782
+ fr.self = self;
3783
+ fr.ca = ca;
3784
+ fr.slab_axes = slab_axes;
3785
+ fr.naxes = naxes;
3786
+ fr.keep_axis = keep_axis;
3787
+ fr.min_count = min_count;
3788
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_u64_body, (VALUE) &fr);
2396
3789
  }
3790
+
2397
3791
  #undef __stddevp_u64_P1EXPR
2398
3792
  #undef __stddevp_u64_P2EXPR
2399
3793
 
2400
3794
  #define __stddevp_f32_P1EXPR(__x) ((double)(__x))
2401
3795
  #define __stddevp_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3796
+ /* The walks can raise part way (a Ruby call per cell in the object
3797
+ lane, an allocation in any lane). Their states live in the caller's
3798
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3799
+ typedef struct {
3800
+ ca_iter_state states[1];
3801
+ VALUE self;
3802
+ CArray *ca;
3803
+ int8_t *slab_axes;
3804
+ int8_t naxes;
3805
+ int keep_axis;
3806
+ ca_size_t min_count;
3807
+ } stddevp_ki_native_f32_frame;
3808
+
2402
3809
  static VALUE
2403
- stddevp_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3810
+ stddevp_ki_native_f32_body (VALUE arg)
2404
3811
  {
3812
+ stddevp_ki_native_f32_frame *fr = (stddevp_ki_native_f32_frame *) arg;
3813
+ VALUE self = fr->self;
3814
+ (void) self;
3815
+ CArray *ca = fr->ca;
3816
+ (void) ca;
3817
+ int8_t *slab_axes = fr->slab_axes;
3818
+ (void) slab_axes;
3819
+ int8_t naxes = fr->naxes;
3820
+ (void) naxes;
3821
+ int keep_axis = fr->keep_axis;
3822
+ (void) keep_axis;
3823
+ ca_size_t min_count = fr->min_count;
3824
+ (void) min_count;
3825
+ #define st (fr->states[0])
2405
3826
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2406
3827
  CArray *co;
2407
3828
  GetCArray(vout, co);
2408
3829
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2409
- ca_iter_state st;
2410
3830
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2411
3831
  slab_axes, naxes, 0);
2412
3832
  if ( rc != CA_ITER_OK ) {
@@ -2450,20 +3870,61 @@ stddevp_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2450
3870
  return rb_float_new(op[0]);
2451
3871
  }
2452
3872
  return vout;
3873
+ #undef st
2453
3874
  }
3875
+
3876
+ static VALUE
3877
+ stddevp_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3878
+ {
3879
+ stddevp_ki_native_f32_frame fr;
3880
+ fr.self = self;
3881
+ fr.ca = ca;
3882
+ fr.slab_axes = slab_axes;
3883
+ fr.naxes = naxes;
3884
+ fr.keep_axis = keep_axis;
3885
+ fr.min_count = min_count;
3886
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_f32_body, (VALUE) &fr);
3887
+ }
3888
+
2454
3889
  #undef __stddevp_f32_P1EXPR
2455
3890
  #undef __stddevp_f32_P2EXPR
2456
3891
 
2457
3892
  #define __stddevp_f64_P1EXPR(__x) ((double)(__x))
2458
3893
  #define __stddevp_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
3894
+ /* The walks can raise part way (a Ruby call per cell in the object
3895
+ lane, an allocation in any lane). Their states live in the caller's
3896
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3897
+ typedef struct {
3898
+ ca_iter_state states[1];
3899
+ VALUE self;
3900
+ CArray *ca;
3901
+ int8_t *slab_axes;
3902
+ int8_t naxes;
3903
+ int keep_axis;
3904
+ ca_size_t min_count;
3905
+ } stddevp_ki_native_f64_frame;
3906
+
2459
3907
  static VALUE
2460
- stddevp_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3908
+ stddevp_ki_native_f64_body (VALUE arg)
2461
3909
  {
3910
+ stddevp_ki_native_f64_frame *fr = (stddevp_ki_native_f64_frame *) arg;
3911
+ VALUE self = fr->self;
3912
+ (void) self;
3913
+ CArray *ca = fr->ca;
3914
+ (void) ca;
3915
+ int8_t *slab_axes = fr->slab_axes;
3916
+ (void) slab_axes;
3917
+ int8_t naxes = fr->naxes;
3918
+ (void) naxes;
3919
+ int keep_axis = fr->keep_axis;
3920
+ (void) keep_axis;
3921
+ ca_size_t min_count = fr->min_count;
3922
+ (void) min_count;
3923
+ #define st (fr->states[0])
2462
3924
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2463
3925
  CArray *co;
2464
3926
  GetCArray(vout, co);
2465
3927
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2466
- ca_iter_state st;
2467
3928
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2468
3929
  slab_axes, naxes, 0);
2469
3930
  if ( rc != CA_ITER_OK ) {
@@ -2507,20 +3968,61 @@ stddevp_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2507
3968
  return rb_float_new(op[0]);
2508
3969
  }
2509
3970
  return vout;
3971
+ #undef st
3972
+ }
3973
+
3974
+ static VALUE
3975
+ stddevp_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
3976
+ {
3977
+ stddevp_ki_native_f64_frame fr;
3978
+ fr.self = self;
3979
+ fr.ca = ca;
3980
+ fr.slab_axes = slab_axes;
3981
+ fr.naxes = naxes;
3982
+ fr.keep_axis = keep_axis;
3983
+ fr.min_count = min_count;
3984
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_f64_body, (VALUE) &fr);
2510
3985
  }
3986
+
2511
3987
  #undef __stddevp_f64_P1EXPR
2512
3988
  #undef __stddevp_f64_P2EXPR
2513
3989
 
2514
3990
  #define __stddevp_cmplx64_P1EXPR(__x) (__x)
2515
3991
  #define __stddevp_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
3992
+ /* The walks can raise part way (a Ruby call per cell in the object
3993
+ lane, an allocation in any lane). Their states live in the caller's
3994
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3995
+ typedef struct {
3996
+ ca_iter_state states[1];
3997
+ VALUE self;
3998
+ CArray *ca;
3999
+ int8_t *slab_axes;
4000
+ int8_t naxes;
4001
+ int keep_axis;
4002
+ ca_size_t min_count;
4003
+ } stddevp_ki_native_cmplx64_frame;
4004
+
2516
4005
  static VALUE
2517
- stddevp_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4006
+ stddevp_ki_native_cmplx64_body (VALUE arg)
2518
4007
  {
4008
+ stddevp_ki_native_cmplx64_frame *fr = (stddevp_ki_native_cmplx64_frame *) arg;
4009
+ VALUE self = fr->self;
4010
+ (void) self;
4011
+ CArray *ca = fr->ca;
4012
+ (void) ca;
4013
+ int8_t *slab_axes = fr->slab_axes;
4014
+ (void) slab_axes;
4015
+ int8_t naxes = fr->naxes;
4016
+ (void) naxes;
4017
+ int keep_axis = fr->keep_axis;
4018
+ (void) keep_axis;
4019
+ ca_size_t min_count = fr->min_count;
4020
+ (void) min_count;
4021
+ #define st (fr->states[0])
2519
4022
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2520
4023
  CArray *co;
2521
4024
  GetCArray(vout, co);
2522
4025
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2523
- ca_iter_state st;
2524
4026
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2525
4027
  slab_axes, naxes, 0);
2526
4028
  if ( rc != CA_ITER_OK ) {
@@ -2564,20 +4066,61 @@ stddevp_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
2564
4066
  return rb_float_new(op[0]);
2565
4067
  }
2566
4068
  return vout;
4069
+ #undef st
4070
+ }
4071
+
4072
+ static VALUE
4073
+ stddevp_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4074
+ {
4075
+ stddevp_ki_native_cmplx64_frame fr;
4076
+ fr.self = self;
4077
+ fr.ca = ca;
4078
+ fr.slab_axes = slab_axes;
4079
+ fr.naxes = naxes;
4080
+ fr.keep_axis = keep_axis;
4081
+ fr.min_count = min_count;
4082
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_cmplx64_body, (VALUE) &fr);
2567
4083
  }
4084
+
2568
4085
  #undef __stddevp_cmplx64_P1EXPR
2569
4086
  #undef __stddevp_cmplx64_P2EXPR
2570
4087
 
2571
4088
  #define __stddevp_cmplx128_P1EXPR(__x) (__x)
2572
4089
  #define __stddevp_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
4090
+ /* The walks can raise part way (a Ruby call per cell in the object
4091
+ lane, an allocation in any lane). Their states live in the caller's
4092
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4093
+ typedef struct {
4094
+ ca_iter_state states[1];
4095
+ VALUE self;
4096
+ CArray *ca;
4097
+ int8_t *slab_axes;
4098
+ int8_t naxes;
4099
+ int keep_axis;
4100
+ ca_size_t min_count;
4101
+ } stddevp_ki_native_cmplx128_frame;
4102
+
2573
4103
  static VALUE
2574
- stddevp_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4104
+ stddevp_ki_native_cmplx128_body (VALUE arg)
2575
4105
  {
4106
+ stddevp_ki_native_cmplx128_frame *fr = (stddevp_ki_native_cmplx128_frame *) arg;
4107
+ VALUE self = fr->self;
4108
+ (void) self;
4109
+ CArray *ca = fr->ca;
4110
+ (void) ca;
4111
+ int8_t *slab_axes = fr->slab_axes;
4112
+ (void) slab_axes;
4113
+ int8_t naxes = fr->naxes;
4114
+ (void) naxes;
4115
+ int keep_axis = fr->keep_axis;
4116
+ (void) keep_axis;
4117
+ ca_size_t min_count = fr->min_count;
4118
+ (void) min_count;
4119
+ #define st (fr->states[0])
2576
4120
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2577
4121
  CArray *co;
2578
4122
  GetCArray(vout, co);
2579
4123
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2580
- ca_iter_state st;
2581
4124
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2582
4125
  slab_axes, naxes, 0);
2583
4126
  if ( rc != CA_ITER_OK ) {
@@ -2621,20 +4164,61 @@ stddevp_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
2621
4164
  return rb_float_new(op[0]);
2622
4165
  }
2623
4166
  return vout;
4167
+ #undef st
4168
+ }
4169
+
4170
+ static VALUE
4171
+ stddevp_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4172
+ {
4173
+ stddevp_ki_native_cmplx128_frame fr;
4174
+ fr.self = self;
4175
+ fr.ca = ca;
4176
+ fr.slab_axes = slab_axes;
4177
+ fr.naxes = naxes;
4178
+ fr.keep_axis = keep_axis;
4179
+ fr.min_count = min_count;
4180
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_cmplx128_body, (VALUE) &fr);
2624
4181
  }
4182
+
2625
4183
  #undef __stddevp_cmplx128_P1EXPR
2626
4184
  #undef __stddevp_cmplx128_P2EXPR
2627
4185
 
2628
4186
  #define __stddevp_bool_P1EXPR(__x) ((double)(__x))
2629
4187
  #define __stddevp_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4188
+ /* The walks can raise part way (a Ruby call per cell in the object
4189
+ lane, an allocation in any lane). Their states live in the caller's
4190
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4191
+ typedef struct {
4192
+ ca_iter_state states[1];
4193
+ VALUE self;
4194
+ CArray *ca;
4195
+ int8_t *slab_axes;
4196
+ int8_t naxes;
4197
+ int keep_axis;
4198
+ ca_size_t min_count;
4199
+ } stddevp_ki_native_bool_frame;
4200
+
2630
4201
  static VALUE
2631
- stddevp_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4202
+ stddevp_ki_native_bool_body (VALUE arg)
2632
4203
  {
4204
+ stddevp_ki_native_bool_frame *fr = (stddevp_ki_native_bool_frame *) arg;
4205
+ VALUE self = fr->self;
4206
+ (void) self;
4207
+ CArray *ca = fr->ca;
4208
+ (void) ca;
4209
+ int8_t *slab_axes = fr->slab_axes;
4210
+ (void) slab_axes;
4211
+ int8_t naxes = fr->naxes;
4212
+ (void) naxes;
4213
+ int keep_axis = fr->keep_axis;
4214
+ (void) keep_axis;
4215
+ ca_size_t min_count = fr->min_count;
4216
+ (void) min_count;
4217
+ #define st (fr->states[0])
2633
4218
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2634
4219
  CArray *co;
2635
4220
  GetCArray(vout, co);
2636
4221
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2637
- ca_iter_state st;
2638
4222
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2639
4223
  slab_axes, naxes, 0);
2640
4224
  if ( rc != CA_ITER_OK ) {
@@ -2678,13 +4262,28 @@ stddevp_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2678
4262
  return rb_float_new(op[0]);
2679
4263
  }
2680
4264
  return vout;
4265
+ #undef st
2681
4266
  }
4267
+
4268
+ static VALUE
4269
+ stddevp_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4270
+ {
4271
+ stddevp_ki_native_bool_frame fr;
4272
+ fr.self = self;
4273
+ fr.ca = ca;
4274
+ fr.slab_axes = slab_axes;
4275
+ fr.naxes = naxes;
4276
+ fr.keep_axis = keep_axis;
4277
+ fr.min_count = min_count;
4278
+ return ca_iter_ensure(1, fr.states, stddevp_ki_native_bool_body, (VALUE) &fr);
4279
+ }
4280
+
2682
4281
  #undef __stddevp_bool_P1EXPR
2683
4282
  #undef __stddevp_bool_P2EXPR
2684
4283
 
2685
- /* The object lane calls Ruby for every cell, so a walk can raise part
2686
- way. Its states live in the caller's frame, and ca_iter_ensure
2687
- finishes them however the body leaves. */
4284
+ /* The walks can raise part way (a Ruby call per cell in the object
4285
+ lane, an allocation in any lane). Their states live in the caller's
4286
+ frame, and ca_iter_ensure finishes them however the body leaves. */
2688
4287
  typedef struct {
2689
4288
  ca_iter_state states[1];
2690
4289
  VALUE self;
@@ -2773,7 +4372,7 @@ stddevp_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxe
2773
4372
  fr.naxes = naxes;
2774
4373
  fr.keep_axis = keep_axis;
2775
4374
  fr.min_count = min_count;
2776
- return ca_iter_ensure(1, fr.states, stddevp_ki_native_object_body, (VALUE) &fr);
4375
+ return ca_iter_ensure_computing(ca, 1, fr.states, stddevp_ki_native_object_body, (VALUE) &fr);
2777
4376
  }
2778
4377
 
2779
4378
 
@@ -2891,14 +4490,40 @@ rb_ca_stddevp_ki (int argc, VALUE *argv, VALUE self)
2891
4490
 
2892
4491
  #define __stddev_i8_P1EXPR(__x) ((double)(__x))
2893
4492
  #define __stddev_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4493
+ /* The walks can raise part way (a Ruby call per cell in the object
4494
+ lane, an allocation in any lane). Their states live in the caller's
4495
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4496
+ typedef struct {
4497
+ ca_iter_state states[1];
4498
+ VALUE self;
4499
+ CArray *ca;
4500
+ int8_t *slab_axes;
4501
+ int8_t naxes;
4502
+ int keep_axis;
4503
+ ca_size_t min_count;
4504
+ } stddev_ki_native_i8_frame;
4505
+
2894
4506
  static VALUE
2895
- stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4507
+ stddev_ki_native_i8_body (VALUE arg)
2896
4508
  {
4509
+ stddev_ki_native_i8_frame *fr = (stddev_ki_native_i8_frame *) arg;
4510
+ VALUE self = fr->self;
4511
+ (void) self;
4512
+ CArray *ca = fr->ca;
4513
+ (void) ca;
4514
+ int8_t *slab_axes = fr->slab_axes;
4515
+ (void) slab_axes;
4516
+ int8_t naxes = fr->naxes;
4517
+ (void) naxes;
4518
+ int keep_axis = fr->keep_axis;
4519
+ (void) keep_axis;
4520
+ ca_size_t min_count = fr->min_count;
4521
+ (void) min_count;
4522
+ #define st (fr->states[0])
2897
4523
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2898
4524
  CArray *co;
2899
4525
  GetCArray(vout, co);
2900
4526
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2901
- ca_iter_state st;
2902
4527
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2903
4528
  slab_axes, naxes, 0);
2904
4529
  if ( rc != CA_ITER_OK ) {
@@ -2913,7 +4538,7 @@ stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2913
4538
  /* Pass 1: sum = Σx (+ masked_cnt) */
2914
4539
  double sum = 0.0;
2915
4540
  ca_size_t masked_cnt = 0;
2916
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __stddev_i8_P1EXPR, masked_cnt);
4541
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(int8_t, double, st, p, m, sum, 0.0, __stddev_i8_P1EXPR, masked_cnt);
2917
4542
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2918
4543
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
2919
4544
  if ( __trigger ) {
@@ -2928,7 +4553,7 @@ stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2928
4553
  /* Pass 2: M2 = Σ (x - mean)² */
2929
4554
  double M2 = 0.0;
2930
4555
  ca_size_t __unused_mc = 0;
2931
- CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __stddev_i8_P2EXPR, __unused_mc);
4556
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __stddev_i8_P2EXPR, __unused_mc);
2932
4557
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
2933
4558
  }
2934
4559
  }
@@ -2942,20 +4567,61 @@ stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2942
4567
  return rb_float_new(op[0]);
2943
4568
  }
2944
4569
  return vout;
4570
+ #undef st
4571
+ }
4572
+
4573
+ static VALUE
4574
+ stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4575
+ {
4576
+ stddev_ki_native_i8_frame fr;
4577
+ fr.self = self;
4578
+ fr.ca = ca;
4579
+ fr.slab_axes = slab_axes;
4580
+ fr.naxes = naxes;
4581
+ fr.keep_axis = keep_axis;
4582
+ fr.min_count = min_count;
4583
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_i8_body, (VALUE) &fr);
2945
4584
  }
4585
+
2946
4586
  #undef __stddev_i8_P1EXPR
2947
4587
  #undef __stddev_i8_P2EXPR
2948
4588
 
2949
4589
  #define __stddev_u8_P1EXPR(__x) ((double)(__x))
2950
4590
  #define __stddev_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4591
+ /* The walks can raise part way (a Ruby call per cell in the object
4592
+ lane, an allocation in any lane). Their states live in the caller's
4593
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4594
+ typedef struct {
4595
+ ca_iter_state states[1];
4596
+ VALUE self;
4597
+ CArray *ca;
4598
+ int8_t *slab_axes;
4599
+ int8_t naxes;
4600
+ int keep_axis;
4601
+ ca_size_t min_count;
4602
+ } stddev_ki_native_u8_frame;
4603
+
2951
4604
  static VALUE
2952
- stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4605
+ stddev_ki_native_u8_body (VALUE arg)
2953
4606
  {
4607
+ stddev_ki_native_u8_frame *fr = (stddev_ki_native_u8_frame *) arg;
4608
+ VALUE self = fr->self;
4609
+ (void) self;
4610
+ CArray *ca = fr->ca;
4611
+ (void) ca;
4612
+ int8_t *slab_axes = fr->slab_axes;
4613
+ (void) slab_axes;
4614
+ int8_t naxes = fr->naxes;
4615
+ (void) naxes;
4616
+ int keep_axis = fr->keep_axis;
4617
+ (void) keep_axis;
4618
+ ca_size_t min_count = fr->min_count;
4619
+ (void) min_count;
4620
+ #define st (fr->states[0])
2954
4621
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2955
4622
  CArray *co;
2956
4623
  GetCArray(vout, co);
2957
4624
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2958
- ca_iter_state st;
2959
4625
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2960
4626
  slab_axes, naxes, 0);
2961
4627
  if ( rc != CA_ITER_OK ) {
@@ -2970,7 +4636,7 @@ stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2970
4636
  /* Pass 1: sum = Σx (+ masked_cnt) */
2971
4637
  double sum = 0.0;
2972
4638
  ca_size_t masked_cnt = 0;
2973
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __stddev_u8_P1EXPR, masked_cnt);
4639
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(uint8_t, double, st, p, m, sum, 0.0, __stddev_u8_P1EXPR, masked_cnt);
2974
4640
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2975
4641
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
2976
4642
  if ( __trigger ) {
@@ -2985,7 +4651,7 @@ stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2985
4651
  /* Pass 2: M2 = Σ (x - mean)² */
2986
4652
  double M2 = 0.0;
2987
4653
  ca_size_t __unused_mc = 0;
2988
- CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __stddev_u8_P2EXPR, __unused_mc);
4654
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __stddev_u8_P2EXPR, __unused_mc);
2989
4655
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
2990
4656
  }
2991
4657
  }
@@ -2999,20 +4665,61 @@ stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2999
4665
  return rb_float_new(op[0]);
3000
4666
  }
3001
4667
  return vout;
4668
+ #undef st
4669
+ }
4670
+
4671
+ static VALUE
4672
+ stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4673
+ {
4674
+ stddev_ki_native_u8_frame fr;
4675
+ fr.self = self;
4676
+ fr.ca = ca;
4677
+ fr.slab_axes = slab_axes;
4678
+ fr.naxes = naxes;
4679
+ fr.keep_axis = keep_axis;
4680
+ fr.min_count = min_count;
4681
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_u8_body, (VALUE) &fr);
3002
4682
  }
4683
+
3003
4684
  #undef __stddev_u8_P1EXPR
3004
4685
  #undef __stddev_u8_P2EXPR
3005
4686
 
3006
4687
  #define __stddev_i16_P1EXPR(__x) ((double)(__x))
3007
4688
  #define __stddev_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4689
+ /* The walks can raise part way (a Ruby call per cell in the object
4690
+ lane, an allocation in any lane). Their states live in the caller's
4691
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4692
+ typedef struct {
4693
+ ca_iter_state states[1];
4694
+ VALUE self;
4695
+ CArray *ca;
4696
+ int8_t *slab_axes;
4697
+ int8_t naxes;
4698
+ int keep_axis;
4699
+ ca_size_t min_count;
4700
+ } stddev_ki_native_i16_frame;
4701
+
3008
4702
  static VALUE
3009
- stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4703
+ stddev_ki_native_i16_body (VALUE arg)
3010
4704
  {
4705
+ stddev_ki_native_i16_frame *fr = (stddev_ki_native_i16_frame *) arg;
4706
+ VALUE self = fr->self;
4707
+ (void) self;
4708
+ CArray *ca = fr->ca;
4709
+ (void) ca;
4710
+ int8_t *slab_axes = fr->slab_axes;
4711
+ (void) slab_axes;
4712
+ int8_t naxes = fr->naxes;
4713
+ (void) naxes;
4714
+ int keep_axis = fr->keep_axis;
4715
+ (void) keep_axis;
4716
+ ca_size_t min_count = fr->min_count;
4717
+ (void) min_count;
4718
+ #define st (fr->states[0])
3011
4719
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3012
4720
  CArray *co;
3013
4721
  GetCArray(vout, co);
3014
4722
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3015
- ca_iter_state st;
3016
4723
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3017
4724
  slab_axes, naxes, 0);
3018
4725
  if ( rc != CA_ITER_OK ) {
@@ -3027,7 +4734,7 @@ stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3027
4734
  /* Pass 1: sum = Σx (+ masked_cnt) */
3028
4735
  double sum = 0.0;
3029
4736
  ca_size_t masked_cnt = 0;
3030
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __stddev_i16_P1EXPR, masked_cnt);
4737
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_int16_t, double, st, p, m, sum, 0.0, __stddev_i16_P1EXPR, masked_cnt);
3031
4738
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3032
4739
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3033
4740
  if ( __trigger ) {
@@ -3042,7 +4749,7 @@ stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3042
4749
  /* Pass 2: M2 = Σ (x - mean)² */
3043
4750
  double M2 = 0.0;
3044
4751
  ca_size_t __unused_mc = 0;
3045
- CA_SLAB_REDUCE_SUM8_EX(ca_u_int16_t, double, st, p, m, M2, 0.0, __stddev_i16_P2EXPR, __unused_mc);
4752
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_int16_t, int64_t, st, p, m, M2, 0.0, mean, __stddev_i16_P2EXPR, __unused_mc);
3046
4753
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3047
4754
  }
3048
4755
  }
@@ -3056,20 +4763,61 @@ stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3056
4763
  return rb_float_new(op[0]);
3057
4764
  }
3058
4765
  return vout;
4766
+ #undef st
4767
+ }
4768
+
4769
+ static VALUE
4770
+ stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4771
+ {
4772
+ stddev_ki_native_i16_frame fr;
4773
+ fr.self = self;
4774
+ fr.ca = ca;
4775
+ fr.slab_axes = slab_axes;
4776
+ fr.naxes = naxes;
4777
+ fr.keep_axis = keep_axis;
4778
+ fr.min_count = min_count;
4779
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_i16_body, (VALUE) &fr);
3059
4780
  }
4781
+
3060
4782
  #undef __stddev_i16_P1EXPR
3061
4783
  #undef __stddev_i16_P2EXPR
3062
4784
 
3063
4785
  #define __stddev_u16_P1EXPR(__x) ((double)(__x))
3064
4786
  #define __stddev_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4787
+ /* The walks can raise part way (a Ruby call per cell in the object
4788
+ lane, an allocation in any lane). Their states live in the caller's
4789
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4790
+ typedef struct {
4791
+ ca_iter_state states[1];
4792
+ VALUE self;
4793
+ CArray *ca;
4794
+ int8_t *slab_axes;
4795
+ int8_t naxes;
4796
+ int keep_axis;
4797
+ ca_size_t min_count;
4798
+ } stddev_ki_native_u16_frame;
4799
+
3065
4800
  static VALUE
3066
- stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4801
+ stddev_ki_native_u16_body (VALUE arg)
3067
4802
  {
4803
+ stddev_ki_native_u16_frame *fr = (stddev_ki_native_u16_frame *) arg;
4804
+ VALUE self = fr->self;
4805
+ (void) self;
4806
+ CArray *ca = fr->ca;
4807
+ (void) ca;
4808
+ int8_t *slab_axes = fr->slab_axes;
4809
+ (void) slab_axes;
4810
+ int8_t naxes = fr->naxes;
4811
+ (void) naxes;
4812
+ int keep_axis = fr->keep_axis;
4813
+ (void) keep_axis;
4814
+ ca_size_t min_count = fr->min_count;
4815
+ (void) min_count;
4816
+ #define st (fr->states[0])
3068
4817
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3069
4818
  CArray *co;
3070
4819
  GetCArray(vout, co);
3071
4820
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3072
- ca_iter_state st;
3073
4821
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3074
4822
  slab_axes, naxes, 0);
3075
4823
  if ( rc != CA_ITER_OK ) {
@@ -3084,7 +4832,7 @@ stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3084
4832
  /* Pass 1: sum = Σx (+ masked_cnt) */
3085
4833
  double sum = 0.0;
3086
4834
  ca_size_t masked_cnt = 0;
3087
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __stddev_u16_P1EXPR, masked_cnt);
4835
+ CA_SLAB_REDUCE_SUM8_NARROW_EX(ca_u_uint16_t, double, st, p, m, sum, 0.0, __stddev_u16_P1EXPR, masked_cnt);
3088
4836
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3089
4837
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3090
4838
  if ( __trigger ) {
@@ -3099,7 +4847,7 @@ stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3099
4847
  /* Pass 2: M2 = Σ (x - mean)² */
3100
4848
  double M2 = 0.0;
3101
4849
  ca_size_t __unused_mc = 0;
3102
- CA_SLAB_REDUCE_SUM8_EX(ca_u_uint16_t, double, st, p, m, M2, 0.0, __stddev_u16_P2EXPR, __unused_mc);
4850
+ CA_SLAB_REDUCE_M2_NARROW_EX(ca_u_uint16_t, int64_t, st, p, m, M2, 0.0, mean, __stddev_u16_P2EXPR, __unused_mc);
3103
4851
  op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3104
4852
  }
3105
4853
  }
@@ -3113,20 +4861,61 @@ stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3113
4861
  return rb_float_new(op[0]);
3114
4862
  }
3115
4863
  return vout;
4864
+ #undef st
3116
4865
  }
4866
+
4867
+ static VALUE
4868
+ stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4869
+ {
4870
+ stddev_ki_native_u16_frame fr;
4871
+ fr.self = self;
4872
+ fr.ca = ca;
4873
+ fr.slab_axes = slab_axes;
4874
+ fr.naxes = naxes;
4875
+ fr.keep_axis = keep_axis;
4876
+ fr.min_count = min_count;
4877
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_u16_body, (VALUE) &fr);
4878
+ }
4879
+
3117
4880
  #undef __stddev_u16_P1EXPR
3118
4881
  #undef __stddev_u16_P2EXPR
3119
4882
 
3120
4883
  #define __stddev_i32_P1EXPR(__x) ((double)(__x))
3121
4884
  #define __stddev_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4885
+ /* The walks can raise part way (a Ruby call per cell in the object
4886
+ lane, an allocation in any lane). Their states live in the caller's
4887
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4888
+ typedef struct {
4889
+ ca_iter_state states[1];
4890
+ VALUE self;
4891
+ CArray *ca;
4892
+ int8_t *slab_axes;
4893
+ int8_t naxes;
4894
+ int keep_axis;
4895
+ ca_size_t min_count;
4896
+ } stddev_ki_native_i32_frame;
4897
+
3122
4898
  static VALUE
3123
- stddev_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4899
+ stddev_ki_native_i32_body (VALUE arg)
3124
4900
  {
4901
+ stddev_ki_native_i32_frame *fr = (stddev_ki_native_i32_frame *) arg;
4902
+ VALUE self = fr->self;
4903
+ (void) self;
4904
+ CArray *ca = fr->ca;
4905
+ (void) ca;
4906
+ int8_t *slab_axes = fr->slab_axes;
4907
+ (void) slab_axes;
4908
+ int8_t naxes = fr->naxes;
4909
+ (void) naxes;
4910
+ int keep_axis = fr->keep_axis;
4911
+ (void) keep_axis;
4912
+ ca_size_t min_count = fr->min_count;
4913
+ (void) min_count;
4914
+ #define st (fr->states[0])
3125
4915
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3126
4916
  CArray *co;
3127
4917
  GetCArray(vout, co);
3128
4918
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3129
- ca_iter_state st;
3130
4919
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3131
4920
  slab_axes, naxes, 0);
3132
4921
  if ( rc != CA_ITER_OK ) {
@@ -3170,20 +4959,61 @@ stddev_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3170
4959
  return rb_float_new(op[0]);
3171
4960
  }
3172
4961
  return vout;
4962
+ #undef st
4963
+ }
4964
+
4965
+ static VALUE
4966
+ stddev_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4967
+ {
4968
+ stddev_ki_native_i32_frame fr;
4969
+ fr.self = self;
4970
+ fr.ca = ca;
4971
+ fr.slab_axes = slab_axes;
4972
+ fr.naxes = naxes;
4973
+ fr.keep_axis = keep_axis;
4974
+ fr.min_count = min_count;
4975
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_i32_body, (VALUE) &fr);
3173
4976
  }
4977
+
3174
4978
  #undef __stddev_i32_P1EXPR
3175
4979
  #undef __stddev_i32_P2EXPR
3176
4980
 
3177
4981
  #define __stddev_u32_P1EXPR(__x) ((double)(__x))
3178
4982
  #define __stddev_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
4983
+ /* The walks can raise part way (a Ruby call per cell in the object
4984
+ lane, an allocation in any lane). Their states live in the caller's
4985
+ frame, and ca_iter_ensure finishes them however the body leaves. */
4986
+ typedef struct {
4987
+ ca_iter_state states[1];
4988
+ VALUE self;
4989
+ CArray *ca;
4990
+ int8_t *slab_axes;
4991
+ int8_t naxes;
4992
+ int keep_axis;
4993
+ ca_size_t min_count;
4994
+ } stddev_ki_native_u32_frame;
4995
+
3179
4996
  static VALUE
3180
- stddev_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
4997
+ stddev_ki_native_u32_body (VALUE arg)
3181
4998
  {
4999
+ stddev_ki_native_u32_frame *fr = (stddev_ki_native_u32_frame *) arg;
5000
+ VALUE self = fr->self;
5001
+ (void) self;
5002
+ CArray *ca = fr->ca;
5003
+ (void) ca;
5004
+ int8_t *slab_axes = fr->slab_axes;
5005
+ (void) slab_axes;
5006
+ int8_t naxes = fr->naxes;
5007
+ (void) naxes;
5008
+ int keep_axis = fr->keep_axis;
5009
+ (void) keep_axis;
5010
+ ca_size_t min_count = fr->min_count;
5011
+ (void) min_count;
5012
+ #define st (fr->states[0])
3182
5013
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3183
5014
  CArray *co;
3184
5015
  GetCArray(vout, co);
3185
5016
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3186
- ca_iter_state st;
3187
5017
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3188
5018
  slab_axes, naxes, 0);
3189
5019
  if ( rc != CA_ITER_OK ) {
@@ -3227,20 +5057,61 @@ stddev_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3227
5057
  return rb_float_new(op[0]);
3228
5058
  }
3229
5059
  return vout;
5060
+ #undef st
5061
+ }
5062
+
5063
+ static VALUE
5064
+ stddev_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5065
+ {
5066
+ stddev_ki_native_u32_frame fr;
5067
+ fr.self = self;
5068
+ fr.ca = ca;
5069
+ fr.slab_axes = slab_axes;
5070
+ fr.naxes = naxes;
5071
+ fr.keep_axis = keep_axis;
5072
+ fr.min_count = min_count;
5073
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_u32_body, (VALUE) &fr);
3230
5074
  }
5075
+
3231
5076
  #undef __stddev_u32_P1EXPR
3232
5077
  #undef __stddev_u32_P2EXPR
3233
5078
 
3234
5079
  #define __stddev_i64_P1EXPR(__x) ((double)(__x))
3235
5080
  #define __stddev_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
5081
+ /* The walks can raise part way (a Ruby call per cell in the object
5082
+ lane, an allocation in any lane). Their states live in the caller's
5083
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5084
+ typedef struct {
5085
+ ca_iter_state states[1];
5086
+ VALUE self;
5087
+ CArray *ca;
5088
+ int8_t *slab_axes;
5089
+ int8_t naxes;
5090
+ int keep_axis;
5091
+ ca_size_t min_count;
5092
+ } stddev_ki_native_i64_frame;
5093
+
3236
5094
  static VALUE
3237
- stddev_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5095
+ stddev_ki_native_i64_body (VALUE arg)
3238
5096
  {
5097
+ stddev_ki_native_i64_frame *fr = (stddev_ki_native_i64_frame *) arg;
5098
+ VALUE self = fr->self;
5099
+ (void) self;
5100
+ CArray *ca = fr->ca;
5101
+ (void) ca;
5102
+ int8_t *slab_axes = fr->slab_axes;
5103
+ (void) slab_axes;
5104
+ int8_t naxes = fr->naxes;
5105
+ (void) naxes;
5106
+ int keep_axis = fr->keep_axis;
5107
+ (void) keep_axis;
5108
+ ca_size_t min_count = fr->min_count;
5109
+ (void) min_count;
5110
+ #define st (fr->states[0])
3239
5111
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3240
5112
  CArray *co;
3241
5113
  GetCArray(vout, co);
3242
5114
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3243
- ca_iter_state st;
3244
5115
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3245
5116
  slab_axes, naxes, 0);
3246
5117
  if ( rc != CA_ITER_OK ) {
@@ -3284,20 +5155,61 @@ stddev_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3284
5155
  return rb_float_new(op[0]);
3285
5156
  }
3286
5157
  return vout;
5158
+ #undef st
5159
+ }
5160
+
5161
+ static VALUE
5162
+ stddev_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5163
+ {
5164
+ stddev_ki_native_i64_frame fr;
5165
+ fr.self = self;
5166
+ fr.ca = ca;
5167
+ fr.slab_axes = slab_axes;
5168
+ fr.naxes = naxes;
5169
+ fr.keep_axis = keep_axis;
5170
+ fr.min_count = min_count;
5171
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_i64_body, (VALUE) &fr);
3287
5172
  }
5173
+
3288
5174
  #undef __stddev_i64_P1EXPR
3289
5175
  #undef __stddev_i64_P2EXPR
3290
5176
 
3291
5177
  #define __stddev_u64_P1EXPR(__x) ((double)(__x))
3292
5178
  #define __stddev_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
5179
+ /* The walks can raise part way (a Ruby call per cell in the object
5180
+ lane, an allocation in any lane). Their states live in the caller's
5181
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5182
+ typedef struct {
5183
+ ca_iter_state states[1];
5184
+ VALUE self;
5185
+ CArray *ca;
5186
+ int8_t *slab_axes;
5187
+ int8_t naxes;
5188
+ int keep_axis;
5189
+ ca_size_t min_count;
5190
+ } stddev_ki_native_u64_frame;
5191
+
3293
5192
  static VALUE
3294
- stddev_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5193
+ stddev_ki_native_u64_body (VALUE arg)
3295
5194
  {
5195
+ stddev_ki_native_u64_frame *fr = (stddev_ki_native_u64_frame *) arg;
5196
+ VALUE self = fr->self;
5197
+ (void) self;
5198
+ CArray *ca = fr->ca;
5199
+ (void) ca;
5200
+ int8_t *slab_axes = fr->slab_axes;
5201
+ (void) slab_axes;
5202
+ int8_t naxes = fr->naxes;
5203
+ (void) naxes;
5204
+ int keep_axis = fr->keep_axis;
5205
+ (void) keep_axis;
5206
+ ca_size_t min_count = fr->min_count;
5207
+ (void) min_count;
5208
+ #define st (fr->states[0])
3296
5209
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3297
5210
  CArray *co;
3298
5211
  GetCArray(vout, co);
3299
5212
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3300
- ca_iter_state st;
3301
5213
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3302
5214
  slab_axes, naxes, 0);
3303
5215
  if ( rc != CA_ITER_OK ) {
@@ -3341,20 +5253,61 @@ stddev_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3341
5253
  return rb_float_new(op[0]);
3342
5254
  }
3343
5255
  return vout;
5256
+ #undef st
3344
5257
  }
5258
+
5259
+ static VALUE
5260
+ stddev_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5261
+ {
5262
+ stddev_ki_native_u64_frame fr;
5263
+ fr.self = self;
5264
+ fr.ca = ca;
5265
+ fr.slab_axes = slab_axes;
5266
+ fr.naxes = naxes;
5267
+ fr.keep_axis = keep_axis;
5268
+ fr.min_count = min_count;
5269
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_u64_body, (VALUE) &fr);
5270
+ }
5271
+
3345
5272
  #undef __stddev_u64_P1EXPR
3346
5273
  #undef __stddev_u64_P2EXPR
3347
5274
 
3348
5275
  #define __stddev_f32_P1EXPR(__x) ((double)(__x))
3349
5276
  #define __stddev_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
5277
+ /* The walks can raise part way (a Ruby call per cell in the object
5278
+ lane, an allocation in any lane). Their states live in the caller's
5279
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5280
+ typedef struct {
5281
+ ca_iter_state states[1];
5282
+ VALUE self;
5283
+ CArray *ca;
5284
+ int8_t *slab_axes;
5285
+ int8_t naxes;
5286
+ int keep_axis;
5287
+ ca_size_t min_count;
5288
+ } stddev_ki_native_f32_frame;
5289
+
3350
5290
  static VALUE
3351
- stddev_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5291
+ stddev_ki_native_f32_body (VALUE arg)
3352
5292
  {
5293
+ stddev_ki_native_f32_frame *fr = (stddev_ki_native_f32_frame *) arg;
5294
+ VALUE self = fr->self;
5295
+ (void) self;
5296
+ CArray *ca = fr->ca;
5297
+ (void) ca;
5298
+ int8_t *slab_axes = fr->slab_axes;
5299
+ (void) slab_axes;
5300
+ int8_t naxes = fr->naxes;
5301
+ (void) naxes;
5302
+ int keep_axis = fr->keep_axis;
5303
+ (void) keep_axis;
5304
+ ca_size_t min_count = fr->min_count;
5305
+ (void) min_count;
5306
+ #define st (fr->states[0])
3353
5307
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3354
5308
  CArray *co;
3355
5309
  GetCArray(vout, co);
3356
5310
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3357
- ca_iter_state st;
3358
5311
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3359
5312
  slab_axes, naxes, 0);
3360
5313
  if ( rc != CA_ITER_OK ) {
@@ -3398,20 +5351,61 @@ stddev_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3398
5351
  return rb_float_new(op[0]);
3399
5352
  }
3400
5353
  return vout;
5354
+ #undef st
5355
+ }
5356
+
5357
+ static VALUE
5358
+ stddev_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5359
+ {
5360
+ stddev_ki_native_f32_frame fr;
5361
+ fr.self = self;
5362
+ fr.ca = ca;
5363
+ fr.slab_axes = slab_axes;
5364
+ fr.naxes = naxes;
5365
+ fr.keep_axis = keep_axis;
5366
+ fr.min_count = min_count;
5367
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_f32_body, (VALUE) &fr);
3401
5368
  }
5369
+
3402
5370
  #undef __stddev_f32_P1EXPR
3403
5371
  #undef __stddev_f32_P2EXPR
3404
5372
 
3405
5373
  #define __stddev_f64_P1EXPR(__x) ((double)(__x))
3406
5374
  #define __stddev_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
5375
+ /* The walks can raise part way (a Ruby call per cell in the object
5376
+ lane, an allocation in any lane). Their states live in the caller's
5377
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5378
+ typedef struct {
5379
+ ca_iter_state states[1];
5380
+ VALUE self;
5381
+ CArray *ca;
5382
+ int8_t *slab_axes;
5383
+ int8_t naxes;
5384
+ int keep_axis;
5385
+ ca_size_t min_count;
5386
+ } stddev_ki_native_f64_frame;
5387
+
3407
5388
  static VALUE
3408
- stddev_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5389
+ stddev_ki_native_f64_body (VALUE arg)
3409
5390
  {
5391
+ stddev_ki_native_f64_frame *fr = (stddev_ki_native_f64_frame *) arg;
5392
+ VALUE self = fr->self;
5393
+ (void) self;
5394
+ CArray *ca = fr->ca;
5395
+ (void) ca;
5396
+ int8_t *slab_axes = fr->slab_axes;
5397
+ (void) slab_axes;
5398
+ int8_t naxes = fr->naxes;
5399
+ (void) naxes;
5400
+ int keep_axis = fr->keep_axis;
5401
+ (void) keep_axis;
5402
+ ca_size_t min_count = fr->min_count;
5403
+ (void) min_count;
5404
+ #define st (fr->states[0])
3410
5405
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3411
5406
  CArray *co;
3412
5407
  GetCArray(vout, co);
3413
5408
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3414
- ca_iter_state st;
3415
5409
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3416
5410
  slab_axes, naxes, 0);
3417
5411
  if ( rc != CA_ITER_OK ) {
@@ -3455,20 +5449,61 @@ stddev_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3455
5449
  return rb_float_new(op[0]);
3456
5450
  }
3457
5451
  return vout;
5452
+ #undef st
5453
+ }
5454
+
5455
+ static VALUE
5456
+ stddev_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5457
+ {
5458
+ stddev_ki_native_f64_frame fr;
5459
+ fr.self = self;
5460
+ fr.ca = ca;
5461
+ fr.slab_axes = slab_axes;
5462
+ fr.naxes = naxes;
5463
+ fr.keep_axis = keep_axis;
5464
+ fr.min_count = min_count;
5465
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_f64_body, (VALUE) &fr);
3458
5466
  }
5467
+
3459
5468
  #undef __stddev_f64_P1EXPR
3460
5469
  #undef __stddev_f64_P2EXPR
3461
5470
 
3462
5471
  #define __stddev_cmplx64_P1EXPR(__x) (__x)
3463
5472
  #define __stddev_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
5473
+ /* The walks can raise part way (a Ruby call per cell in the object
5474
+ lane, an allocation in any lane). Their states live in the caller's
5475
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5476
+ typedef struct {
5477
+ ca_iter_state states[1];
5478
+ VALUE self;
5479
+ CArray *ca;
5480
+ int8_t *slab_axes;
5481
+ int8_t naxes;
5482
+ int keep_axis;
5483
+ ca_size_t min_count;
5484
+ } stddev_ki_native_cmplx64_frame;
5485
+
3464
5486
  static VALUE
3465
- stddev_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5487
+ stddev_ki_native_cmplx64_body (VALUE arg)
3466
5488
  {
5489
+ stddev_ki_native_cmplx64_frame *fr = (stddev_ki_native_cmplx64_frame *) arg;
5490
+ VALUE self = fr->self;
5491
+ (void) self;
5492
+ CArray *ca = fr->ca;
5493
+ (void) ca;
5494
+ int8_t *slab_axes = fr->slab_axes;
5495
+ (void) slab_axes;
5496
+ int8_t naxes = fr->naxes;
5497
+ (void) naxes;
5498
+ int keep_axis = fr->keep_axis;
5499
+ (void) keep_axis;
5500
+ ca_size_t min_count = fr->min_count;
5501
+ (void) min_count;
5502
+ #define st (fr->states[0])
3467
5503
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3468
5504
  CArray *co;
3469
5505
  GetCArray(vout, co);
3470
5506
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3471
- ca_iter_state st;
3472
5507
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3473
5508
  slab_axes, naxes, 0);
3474
5509
  if ( rc != CA_ITER_OK ) {
@@ -3512,20 +5547,61 @@ stddev_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxe
3512
5547
  return rb_float_new(op[0]);
3513
5548
  }
3514
5549
  return vout;
5550
+ #undef st
5551
+ }
5552
+
5553
+ static VALUE
5554
+ stddev_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5555
+ {
5556
+ stddev_ki_native_cmplx64_frame fr;
5557
+ fr.self = self;
5558
+ fr.ca = ca;
5559
+ fr.slab_axes = slab_axes;
5560
+ fr.naxes = naxes;
5561
+ fr.keep_axis = keep_axis;
5562
+ fr.min_count = min_count;
5563
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_cmplx64_body, (VALUE) &fr);
3515
5564
  }
5565
+
3516
5566
  #undef __stddev_cmplx64_P1EXPR
3517
5567
  #undef __stddev_cmplx64_P2EXPR
3518
5568
 
3519
5569
  #define __stddev_cmplx128_P1EXPR(__x) (__x)
3520
5570
  #define __stddev_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
5571
+ /* The walks can raise part way (a Ruby call per cell in the object
5572
+ lane, an allocation in any lane). Their states live in the caller's
5573
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5574
+ typedef struct {
5575
+ ca_iter_state states[1];
5576
+ VALUE self;
5577
+ CArray *ca;
5578
+ int8_t *slab_axes;
5579
+ int8_t naxes;
5580
+ int keep_axis;
5581
+ ca_size_t min_count;
5582
+ } stddev_ki_native_cmplx128_frame;
5583
+
3521
5584
  static VALUE
3522
- stddev_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5585
+ stddev_ki_native_cmplx128_body (VALUE arg)
3523
5586
  {
5587
+ stddev_ki_native_cmplx128_frame *fr = (stddev_ki_native_cmplx128_frame *) arg;
5588
+ VALUE self = fr->self;
5589
+ (void) self;
5590
+ CArray *ca = fr->ca;
5591
+ (void) ca;
5592
+ int8_t *slab_axes = fr->slab_axes;
5593
+ (void) slab_axes;
5594
+ int8_t naxes = fr->naxes;
5595
+ (void) naxes;
5596
+ int keep_axis = fr->keep_axis;
5597
+ (void) keep_axis;
5598
+ ca_size_t min_count = fr->min_count;
5599
+ (void) min_count;
5600
+ #define st (fr->states[0])
3524
5601
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3525
5602
  CArray *co;
3526
5603
  GetCArray(vout, co);
3527
5604
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3528
- ca_iter_state st;
3529
5605
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3530
5606
  slab_axes, naxes, 0);
3531
5607
  if ( rc != CA_ITER_OK ) {
@@ -3569,20 +5645,61 @@ stddev_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
3569
5645
  return rb_float_new(op[0]);
3570
5646
  }
3571
5647
  return vout;
5648
+ #undef st
3572
5649
  }
5650
+
5651
+ static VALUE
5652
+ stddev_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5653
+ {
5654
+ stddev_ki_native_cmplx128_frame fr;
5655
+ fr.self = self;
5656
+ fr.ca = ca;
5657
+ fr.slab_axes = slab_axes;
5658
+ fr.naxes = naxes;
5659
+ fr.keep_axis = keep_axis;
5660
+ fr.min_count = min_count;
5661
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_cmplx128_body, (VALUE) &fr);
5662
+ }
5663
+
3573
5664
  #undef __stddev_cmplx128_P1EXPR
3574
5665
  #undef __stddev_cmplx128_P2EXPR
3575
5666
 
3576
5667
  #define __stddev_bool_P1EXPR(__x) ((double)(__x))
3577
5668
  #define __stddev_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
5669
+ /* The walks can raise part way (a Ruby call per cell in the object
5670
+ lane, an allocation in any lane). Their states live in the caller's
5671
+ frame, and ca_iter_ensure finishes them however the body leaves. */
5672
+ typedef struct {
5673
+ ca_iter_state states[1];
5674
+ VALUE self;
5675
+ CArray *ca;
5676
+ int8_t *slab_axes;
5677
+ int8_t naxes;
5678
+ int keep_axis;
5679
+ ca_size_t min_count;
5680
+ } stddev_ki_native_bool_frame;
5681
+
3578
5682
  static VALUE
3579
- stddev_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5683
+ stddev_ki_native_bool_body (VALUE arg)
3580
5684
  {
5685
+ stddev_ki_native_bool_frame *fr = (stddev_ki_native_bool_frame *) arg;
5686
+ VALUE self = fr->self;
5687
+ (void) self;
5688
+ CArray *ca = fr->ca;
5689
+ (void) ca;
5690
+ int8_t *slab_axes = fr->slab_axes;
5691
+ (void) slab_axes;
5692
+ int8_t naxes = fr->naxes;
5693
+ (void) naxes;
5694
+ int keep_axis = fr->keep_axis;
5695
+ (void) keep_axis;
5696
+ ca_size_t min_count = fr->min_count;
5697
+ (void) min_count;
5698
+ #define st (fr->states[0])
3581
5699
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3582
5700
  CArray *co;
3583
5701
  GetCArray(vout, co);
3584
5702
  ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3585
- ca_iter_state st;
3586
5703
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3587
5704
  slab_axes, naxes, 0);
3588
5705
  if ( rc != CA_ITER_OK ) {
@@ -3626,13 +5743,28 @@ stddev_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
3626
5743
  return rb_float_new(op[0]);
3627
5744
  }
3628
5745
  return vout;
5746
+ #undef st
5747
+ }
5748
+
5749
+ static VALUE
5750
+ stddev_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
5751
+ {
5752
+ stddev_ki_native_bool_frame fr;
5753
+ fr.self = self;
5754
+ fr.ca = ca;
5755
+ fr.slab_axes = slab_axes;
5756
+ fr.naxes = naxes;
5757
+ fr.keep_axis = keep_axis;
5758
+ fr.min_count = min_count;
5759
+ return ca_iter_ensure(1, fr.states, stddev_ki_native_bool_body, (VALUE) &fr);
3629
5760
  }
5761
+
3630
5762
  #undef __stddev_bool_P1EXPR
3631
5763
  #undef __stddev_bool_P2EXPR
3632
5764
 
3633
- /* The object lane calls Ruby for every cell, so a walk can raise part
3634
- way. Its states live in the caller's frame, and ca_iter_ensure
3635
- finishes them however the body leaves. */
5765
+ /* The walks can raise part way (a Ruby call per cell in the object
5766
+ lane, an allocation in any lane). Their states live in the caller's
5767
+ frame, and ca_iter_ensure finishes them however the body leaves. */
3636
5768
  typedef struct {
3637
5769
  ca_iter_state states[1];
3638
5770
  VALUE self;
@@ -3721,7 +5853,7 @@ stddev_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
3721
5853
  fr.naxes = naxes;
3722
5854
  fr.keep_axis = keep_axis;
3723
5855
  fr.min_count = min_count;
3724
- return ca_iter_ensure(1, fr.states, stddev_ki_native_object_body, (VALUE) &fr);
5856
+ return ca_iter_ensure_computing(ca, 1, fr.states, stddev_ki_native_object_body, (VALUE) &fr);
3725
5857
  }
3726
5858
 
3727
5859