carray 3.0.4 → 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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +438 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_dispatch.c +19 -20
  7. data/ext/ca_axis_group.c +1 -1
  8. data/ext/ca_categorical_iterator.c +34 -27
  9. data/ext/ca_compare.c +4 -4
  10. data/ext/ca_composite_dispatch.c +9 -9
  11. data/ext/ca_kernel_iterator.c +122 -237
  12. data/ext/ca_kernel_iterator.h +522 -337
  13. data/ext/ca_obj_array.c +69 -19
  14. data/ext/ca_obj_bincmp.c +10 -1
  15. data/ext/ca_obj_binop.c +11 -1
  16. data/ext/ca_obj_bitarray.c +5 -1
  17. data/ext/ca_obj_bitfield.c +60 -43
  18. data/ext/ca_obj_byte_swap.c +4 -1
  19. data/ext/ca_obj_const_string.c +15 -3
  20. data/ext/ca_obj_face.c +44 -1
  21. data/ext/ca_obj_fake.c +3 -1
  22. data/ext/ca_obj_field.c +13 -3
  23. data/ext/ca_obj_grid.c +219 -17
  24. data/ext/ca_obj_meld.c +69 -113
  25. data/ext/ca_obj_moncmp.c +9 -1
  26. data/ext/ca_obj_monop.c +86 -12
  27. data/ext/ca_obj_object.c +118 -32
  28. data/ext/ca_obj_record.c +3 -0
  29. data/ext/ca_obj_reduce.c +19 -1
  30. data/ext/ca_obj_refer.c +80 -26
  31. data/ext/ca_obj_remap.c +69 -10
  32. data/ext/ca_obj_roll.c +27 -6
  33. data/ext/ca_obj_select.c +38 -6
  34. data/ext/ca_obj_select_axis.c +1 -0
  35. data/ext/ca_obj_shift.c +32 -7
  36. data/ext/ca_obj_stack.c +311 -111
  37. data/ext/ca_obj_stride.c +159 -64
  38. data/ext/ca_obj_string.c +27 -2
  39. data/ext/ca_obj_tile.c +28 -7
  40. data/ext/ca_obj_transpose.c +8 -4
  41. data/ext/ca_obj_triop.c +12 -1
  42. data/ext/ca_obj_window.c +80 -50
  43. data/ext/ca_op_ipower.c +12 -12
  44. data/ext/ca_sort_kernels.h +6 -3
  45. data/ext/caframe_csv_reader.c +1 -1
  46. data/ext/carray.h +35 -1
  47. data/ext/carray_access.c +43 -67
  48. data/ext/carray_address_basis.c +134 -0
  49. data/ext/carray_attribute.c +32 -0
  50. data/ext/carray_broadcast.c +3 -4
  51. data/ext/carray_build_flags.h +1 -1
  52. data/ext/carray_cast.c +251 -93
  53. data/ext/carray_cast_func.rb +56 -26
  54. data/ext/carray_conversion.c +11 -7
  55. data/ext/carray_core.c +814 -72
  56. data/ext/carray_count.c +6 -0
  57. data/ext/carray_element.c +22 -13
  58. data/ext/carray_factorize.c +20 -20
  59. data/ext/carray_generate.c +8 -2
  60. data/ext/carray_histogram.c +26 -4
  61. data/ext/carray_index_classifier.c +4 -4
  62. data/ext/carray_internal.h +159 -12
  63. data/ext/carray_kernels_bincmp.c +2174 -170
  64. data/ext/carray_kernels_binop.c +25653 -5487
  65. data/ext/carray_kernels_init.c +8 -8
  66. data/ext/carray_kernels_moncmp.c +96 -96
  67. data/ext/carray_kernels_monop.c +12253 -5235
  68. data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
  69. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  70. data/ext/carray_kernels_reduce_cumulative.c +2442 -882
  71. data/ext/carray_kernels_reduce_extreme.c +5658 -1661
  72. data/ext/carray_kernels_reduce_variance.c +2534 -402
  73. data/ext/carray_kernels_scan.c +368 -368
  74. data/ext/carray_kernels_search.c +4551 -604
  75. data/ext/carray_kernels_sort.c +659 -751
  76. data/ext/carray_kernels_triop.c +114 -114
  77. data/ext/carray_key_windows.c +4 -0
  78. data/ext/carray_lazy.c +47 -0
  79. data/ext/carray_loop.c +1 -1
  80. data/ext/carray_mask.c +175 -161
  81. data/ext/carray_median_percentile.c +4 -4
  82. data/ext/carray_memory_view.c +15 -9
  83. data/ext/carray_operator.c +152 -49
  84. data/ext/carray_order.c +230 -10
  85. data/ext/carray_random.c +22 -19
  86. data/ext/carray_scatter.c +24 -7
  87. data/ext/carray_slab.c +128 -29
  88. data/ext/carray_sort.c +224 -16
  89. data/ext/carray_sort_kernel.c +5 -7
  90. data/ext/carray_struct.c +35 -43
  91. data/ext/carray_test.c +74 -19
  92. data/ext/carray_time_text.c +6 -4
  93. data/ext/carray_utils.c +63 -21
  94. data/ext/extconf.rb +11 -0
  95. data/ext/mkkernel.rb +546 -199
  96. data/ext/ruby_carray.c +4 -1
  97. data/ext/version.h +4 -4
  98. data/lib/carray/attribute.rb +42 -5
  99. data/lib/carray/autoload_carray.rb +3 -3
  100. data/lib/carray/autoload_method_extension.rb +5 -3
  101. data/lib/carray/axis_group.rb +13 -7
  102. data/lib/carray/basics.rb +28 -8
  103. data/lib/carray/block_iterator.rb +17 -3
  104. data/lib/carray/categorical.rb +35 -23
  105. data/lib/carray/categorical_iterator.rb +8 -8
  106. data/lib/carray/complex.rb +2 -2
  107. data/lib/carray/conditional.rb +3 -2
  108. data/lib/carray/const_string.rb +10 -0
  109. data/lib/carray/data_type_extension.rb +8 -1
  110. data/lib/carray/fixlen_string.rb +41 -2
  111. data/lib/carray/frame/column_verbs.rb +48 -16
  112. data/lib/carray/frame/concat.rb +17 -3
  113. data/lib/carray/frame/convert.rb +19 -0
  114. data/lib/carray/frame/csv_parser.rb +32 -32
  115. data/lib/carray/frame/describe.rb +4 -2
  116. data/lib/carray/frame/frame.rb +405 -85
  117. data/lib/carray/frame/group.rb +777 -64
  118. data/lib/carray/frame/io.rb +212 -72
  119. data/lib/carray/frame/join.rb +146 -37
  120. data/lib/carray/frame/records.rb +3 -3
  121. data/lib/carray/frame/reshape.rb +89 -11
  122. data/lib/carray/frame/sort.rb +57 -9
  123. data/lib/carray/frame/verbs.rb +384 -49
  124. data/lib/carray/frame/windows.rb +44 -6
  125. data/lib/carray/fuse_source.rb +31 -2
  126. data/lib/carray/inspect.rb +7 -2
  127. data/lib/carray/iterator.rb +32 -0
  128. data/lib/carray/lazy.rb +52 -8
  129. data/lib/carray/mask_gap_fill.rb +37 -17
  130. data/lib/carray/meld_reduce.rb +1 -1
  131. data/lib/carray/methods/choose.rb +3 -2
  132. data/lib/carray/methods/is_in.rb +8 -1
  133. data/lib/carray/methods/meshgrid.rb +3 -1
  134. data/lib/carray/runtime.rb +47 -8
  135. data/lib/carray/segment_iterator.rb +35 -16
  136. data/lib/carray/serialize.rb +53 -19
  137. data/lib/carray/stack.rb +33 -18
  138. data/lib/carray/string.rb +8 -0
  139. data/lib/carray/string_operation_extension.rb +13 -5
  140. data/lib/carray/struct_builder.rb +5 -3
  141. data/lib/carray/time.rb +112 -68
  142. data/lib/carray/window_iterator.rb +16 -4
  143. data/yard-stubs/ca_obj_array.rb +26 -1
  144. data/yard-stubs/ca_obj_transpose.rb +5 -4
  145. data/yard-stubs/carray_attribute.rb +3 -1
  146. data/yard-stubs/carray_cast.rb +10 -5
  147. data/yard-stubs/carray_conversion.rb +13 -3
  148. data/yard-stubs/carray_element.rb +7 -6
  149. data/yard-stubs/carray_mask.rb +28 -4
  150. data/yard-stubs/carray_math.rb +45 -20
  151. data/yard-stubs/carray_memory_view.rb +7 -0
  152. data/yard-stubs/carray_order.rb +100 -4
  153. data/yard-stubs/carray_scatter.rb +7 -5
  154. data/yard-stubs/carray_test.rb +7 -4
  155. 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
- double *op = (double *) co->ptr;
57
- ca_iter_state st;
83
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -78,14 +104,14 @@ variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
78
104
  op_mask = (boolean8_t *) co->mask->ptr;
79
105
  }
80
106
  op_mask[out_i] = 1;
81
- op[out_i++] = (double) 0.0;
107
+ op[out_i++] = (ca_u_float64_t) 0;
82
108
  } else {
83
109
  double mean = sum / (double) n_valid;
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);
88
- op[out_i++] = (double)(M2 / (double)(n_valid));
113
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __variancep_i8_P2EXPR, __unused_mc);
114
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
89
115
  }
90
116
  }
91
117
  ca_iter_state_finish(&st);
@@ -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
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);
101
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
- double *op = (double *) co->ptr;
114
- ca_iter_state st;
181
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -135,14 +202,14 @@ variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
135
202
  op_mask = (boolean8_t *) co->mask->ptr;
136
203
  }
137
204
  op_mask[out_i] = 1;
138
- op[out_i++] = (double) 0.0;
205
+ op[out_i++] = (ca_u_float64_t) 0;
139
206
  } else {
140
207
  double mean = sum / (double) n_valid;
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);
145
- op[out_i++] = (double)(M2 / (double)(n_valid));
211
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __variancep_u8_P2EXPR, __unused_mc);
212
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
146
213
  }
147
214
  }
148
215
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
171
- ca_iter_state st;
279
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -192,14 +300,14 @@ variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
192
300
  op_mask = (boolean8_t *) co->mask->ptr;
193
301
  }
194
302
  op_mask[out_i] = 1;
195
- op[out_i++] = (double) 0.0;
303
+ op[out_i++] = (ca_u_float64_t) 0;
196
304
  } else {
197
305
  double mean = sum / (double) n_valid;
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(int16_t, double, st, p, m, M2, 0.0, __variancep_i16_P2EXPR, __unused_mc);
202
- op[out_i++] = (double)(M2 / (double)(n_valid));
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);
310
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
203
311
  }
204
312
  }
205
313
  ca_iter_state_finish(&st);
@@ -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
215
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);
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
- double *op = (double *) co->ptr;
228
- ca_iter_state st;
377
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -249,14 +398,14 @@ variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
249
398
  op_mask = (boolean8_t *) co->mask->ptr;
250
399
  }
251
400
  op_mask[out_i] = 1;
252
- op[out_i++] = (double) 0.0;
401
+ op[out_i++] = (ca_u_float64_t) 0;
253
402
  } else {
254
403
  double mean = sum / (double) n_valid;
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(uint16_t, double, st, p, m, M2, 0.0, __variancep_u16_P2EXPR, __unused_mc);
259
- op[out_i++] = (double)(M2 / (double)(n_valid));
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);
408
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
260
409
  }
261
410
  }
262
411
  ca_iter_state_finish(&st);
@@ -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
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);
272
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
- double *op = (double *) co->ptr;
285
- ca_iter_state st;
475
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -297,7 +487,7 @@ variancep_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
297
487
  /* Pass 1: sum = Σx (+ masked_cnt) */
298
488
  double sum = 0.0;
299
489
  ca_size_t masked_cnt = 0;
300
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __variancep_i32_P1EXPR, masked_cnt);
490
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, sum, 0.0, __variancep_i32_P1EXPR, masked_cnt);
301
491
  ca_size_t n_valid = st.slab_elements - masked_cnt;
302
492
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
303
493
  if ( __trigger ) {
@@ -306,14 +496,14 @@ variancep_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
306
496
  op_mask = (boolean8_t *) co->mask->ptr;
307
497
  }
308
498
  op_mask[out_i] = 1;
309
- op[out_i++] = (double) 0.0;
499
+ op[out_i++] = (ca_u_float64_t) 0;
310
500
  } else {
311
501
  double mean = sum / (double) n_valid;
312
502
  /* Pass 2: M2 = Σ (x - mean)² */
313
503
  double M2 = 0.0;
314
504
  ca_size_t __unused_mc = 0;
315
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __variancep_i32_P2EXPR, __unused_mc);
316
- op[out_i++] = (double)(M2 / (double)(n_valid));
505
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, M2, 0.0, __variancep_i32_P2EXPR, __unused_mc);
506
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
317
507
  }
318
508
  }
319
509
  ca_iter_state_finish(&st);
@@ -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
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);
329
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
- double *op = (double *) co->ptr;
342
- ca_iter_state st;
573
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -354,7 +585,7 @@ variancep_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
354
585
  /* Pass 1: sum = Σx (+ masked_cnt) */
355
586
  double sum = 0.0;
356
587
  ca_size_t masked_cnt = 0;
357
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __variancep_u32_P1EXPR, masked_cnt);
588
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, sum, 0.0, __variancep_u32_P1EXPR, masked_cnt);
358
589
  ca_size_t n_valid = st.slab_elements - masked_cnt;
359
590
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
360
591
  if ( __trigger ) {
@@ -363,14 +594,14 @@ variancep_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
363
594
  op_mask = (boolean8_t *) co->mask->ptr;
364
595
  }
365
596
  op_mask[out_i] = 1;
366
- op[out_i++] = (double) 0.0;
597
+ op[out_i++] = (ca_u_float64_t) 0;
367
598
  } else {
368
599
  double mean = sum / (double) n_valid;
369
600
  /* Pass 2: M2 = Σ (x - mean)² */
370
601
  double M2 = 0.0;
371
602
  ca_size_t __unused_mc = 0;
372
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __variancep_u32_P2EXPR, __unused_mc);
373
- op[out_i++] = (double)(M2 / (double)(n_valid));
603
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, M2, 0.0, __variancep_u32_P2EXPR, __unused_mc);
604
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
374
605
  }
375
606
  }
376
607
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
399
- ca_iter_state st;
671
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -411,7 +683,7 @@ variancep_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
411
683
  /* Pass 1: sum = Σx (+ masked_cnt) */
412
684
  double sum = 0.0;
413
685
  ca_size_t masked_cnt = 0;
414
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __variancep_i64_P1EXPR, masked_cnt);
686
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, sum, 0.0, __variancep_i64_P1EXPR, masked_cnt);
415
687
  ca_size_t n_valid = st.slab_elements - masked_cnt;
416
688
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
417
689
  if ( __trigger ) {
@@ -420,14 +692,14 @@ variancep_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
420
692
  op_mask = (boolean8_t *) co->mask->ptr;
421
693
  }
422
694
  op_mask[out_i] = 1;
423
- op[out_i++] = (double) 0.0;
695
+ op[out_i++] = (ca_u_float64_t) 0;
424
696
  } else {
425
697
  double mean = sum / (double) n_valid;
426
698
  /* Pass 2: M2 = Σ (x - mean)² */
427
699
  double M2 = 0.0;
428
700
  ca_size_t __unused_mc = 0;
429
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __variancep_i64_P2EXPR, __unused_mc);
430
- op[out_i++] = (double)(M2 / (double)(n_valid));
701
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, M2, 0.0, __variancep_i64_P2EXPR, __unused_mc);
702
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
431
703
  }
432
704
  }
433
705
  ca_iter_state_finish(&st);
@@ -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))
449
- 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)
451
- {
452
- VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
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
+
749
+ static VALUE
750
+ variancep_ki_native_u64_body (VALUE arg)
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])
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
- double *op = (double *) co->ptr;
456
- ca_iter_state st;
769
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -468,7 +781,7 @@ variancep_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
468
781
  /* Pass 1: sum = Σx (+ masked_cnt) */
469
782
  double sum = 0.0;
470
783
  ca_size_t masked_cnt = 0;
471
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __variancep_u64_P1EXPR, masked_cnt);
784
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, sum, 0.0, __variancep_u64_P1EXPR, masked_cnt);
472
785
  ca_size_t n_valid = st.slab_elements - masked_cnt;
473
786
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
474
787
  if ( __trigger ) {
@@ -477,14 +790,14 @@ variancep_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
477
790
  op_mask = (boolean8_t *) co->mask->ptr;
478
791
  }
479
792
  op_mask[out_i] = 1;
480
- op[out_i++] = (double) 0.0;
793
+ op[out_i++] = (ca_u_float64_t) 0;
481
794
  } else {
482
795
  double mean = sum / (double) n_valid;
483
796
  /* Pass 2: M2 = Σ (x - mean)² */
484
797
  double M2 = 0.0;
485
798
  ca_size_t __unused_mc = 0;
486
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __variancep_u64_P2EXPR, __unused_mc);
487
- op[out_i++] = (double)(M2 / (double)(n_valid));
799
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, M2, 0.0, __variancep_u64_P2EXPR, __unused_mc);
800
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
488
801
  }
489
802
  }
490
803
  ca_iter_state_finish(&st);
@@ -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
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);
500
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
- double *op = (double *) co->ptr;
513
- ca_iter_state st;
867
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -525,7 +879,7 @@ variancep_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
525
879
  /* Pass 1: sum = Σx (+ masked_cnt) */
526
880
  double sum = 0.0;
527
881
  ca_size_t masked_cnt = 0;
528
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __variancep_f32_P1EXPR, masked_cnt);
882
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, sum, 0.0, __variancep_f32_P1EXPR, masked_cnt);
529
883
  ca_size_t n_valid = st.slab_elements - masked_cnt;
530
884
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
531
885
  if ( __trigger ) {
@@ -534,14 +888,14 @@ variancep_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
534
888
  op_mask = (boolean8_t *) co->mask->ptr;
535
889
  }
536
890
  op_mask[out_i] = 1;
537
- op[out_i++] = (double) 0.0;
891
+ op[out_i++] = (ca_u_float64_t) 0;
538
892
  } else {
539
893
  double mean = sum / (double) n_valid;
540
894
  /* Pass 2: M2 = Σ (x - mean)² */
541
895
  double M2 = 0.0;
542
896
  ca_size_t __unused_mc = 0;
543
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __variancep_f32_P2EXPR, __unused_mc);
544
- op[out_i++] = (double)(M2 / (double)(n_valid));
897
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, M2, 0.0, __variancep_f32_P2EXPR, __unused_mc);
898
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
545
899
  }
546
900
  }
547
901
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
570
- ca_iter_state st;
965
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -582,7 +977,7 @@ variancep_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
582
977
  /* Pass 1: sum = Σx (+ masked_cnt) */
583
978
  double sum = 0.0;
584
979
  ca_size_t masked_cnt = 0;
585
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __variancep_f64_P1EXPR, masked_cnt);
980
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, sum, 0.0, __variancep_f64_P1EXPR, masked_cnt);
586
981
  ca_size_t n_valid = st.slab_elements - masked_cnt;
587
982
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
588
983
  if ( __trigger ) {
@@ -591,14 +986,14 @@ variancep_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
591
986
  op_mask = (boolean8_t *) co->mask->ptr;
592
987
  }
593
988
  op_mask[out_i] = 1;
594
- op[out_i++] = (double) 0.0;
989
+ op[out_i++] = (ca_u_float64_t) 0;
595
990
  } else {
596
991
  double mean = sum / (double) n_valid;
597
992
  /* Pass 2: M2 = Σ (x - mean)² */
598
993
  double M2 = 0.0;
599
994
  ca_size_t __unused_mc = 0;
600
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __variancep_f64_P2EXPR, __unused_mc);
601
- op[out_i++] = (double)(M2 / (double)(n_valid));
995
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, M2, 0.0, __variancep_f64_P2EXPR, __unused_mc);
996
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
602
997
  }
603
998
  }
604
999
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
627
- ca_iter_state st;
1063
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -637,9 +1073,9 @@ variancep_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t n
637
1073
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
638
1074
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
639
1075
  /* Pass 1: sum = Σx (+ masked_cnt) */
640
- cmplx64_t sum = 0;
1076
+ ca_u_cmplx64_t sum = 0;
641
1077
  ca_size_t masked_cnt = 0;
642
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __variancep_cmplx64_P1EXPR, masked_cnt);
1078
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, ca_u_cmplx64_t, st, p, m, sum, 0, __variancep_cmplx64_P1EXPR, masked_cnt);
643
1079
  ca_size_t n_valid = st.slab_elements - masked_cnt;
644
1080
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
645
1081
  if ( __trigger ) {
@@ -648,14 +1084,14 @@ variancep_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t n
648
1084
  op_mask = (boolean8_t *) co->mask->ptr;
649
1085
  }
650
1086
  op_mask[out_i] = 1;
651
- op[out_i++] = (double) 0.0;
1087
+ op[out_i++] = (ca_u_float64_t) 0;
652
1088
  } else {
653
- cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
1089
+ ca_u_cmplx64_t mean = sum / (ca_u_cmplx64_t)(double) n_valid;
654
1090
  /* Pass 2: M2 = Σ (x - mean)² */
655
1091
  double M2 = 0.0;
656
1092
  ca_size_t __unused_mc = 0;
657
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __variancep_cmplx64_P2EXPR, __unused_mc);
658
- op[out_i++] = (double)(M2 / (double)(n_valid));
1093
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, double, st, p, m, M2, 0.0, __variancep_cmplx64_P2EXPR, __unused_mc);
1094
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
659
1095
  }
660
1096
  }
661
1097
  ca_iter_state_finish(&st);
@@ -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
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);
671
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
- double *op = (double *) co->ptr;
684
- ca_iter_state st;
1161
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -694,9 +1171,9 @@ variancep_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t
694
1171
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
695
1172
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
696
1173
  /* Pass 1: sum = Σx (+ masked_cnt) */
697
- cmplx128_t sum = 0;
1174
+ ca_u_cmplx128_t sum = 0;
698
1175
  ca_size_t masked_cnt = 0;
699
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __variancep_cmplx128_P1EXPR, masked_cnt);
1176
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, ca_u_cmplx128_t, st, p, m, sum, 0, __variancep_cmplx128_P1EXPR, masked_cnt);
700
1177
  ca_size_t n_valid = st.slab_elements - masked_cnt;
701
1178
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
702
1179
  if ( __trigger ) {
@@ -705,14 +1182,14 @@ variancep_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t
705
1182
  op_mask = (boolean8_t *) co->mask->ptr;
706
1183
  }
707
1184
  op_mask[out_i] = 1;
708
- op[out_i++] = (double) 0.0;
1185
+ op[out_i++] = (ca_u_float64_t) 0;
709
1186
  } else {
710
- cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
1187
+ ca_u_cmplx128_t mean = sum / (ca_u_cmplx128_t)(double) n_valid;
711
1188
  /* Pass 2: M2 = Σ (x - mean)² */
712
1189
  double M2 = 0.0;
713
1190
  ca_size_t __unused_mc = 0;
714
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __variancep_cmplx128_P2EXPR, __unused_mc);
715
- op[out_i++] = (double)(M2 / (double)(n_valid));
1191
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, double, st, p, m, M2, 0.0, __variancep_cmplx128_P2EXPR, __unused_mc);
1192
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
716
1193
  }
717
1194
  }
718
1195
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
741
- ca_iter_state st;
1259
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -762,14 +1280,14 @@ variancep_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxe
762
1280
  op_mask = (boolean8_t *) co->mask->ptr;
763
1281
  }
764
1282
  op_mask[out_i] = 1;
765
- op[out_i++] = (double) 0.0;
1283
+ op[out_i++] = (ca_u_float64_t) 0;
766
1284
  } else {
767
1285
  double mean = sum / (double) n_valid;
768
1286
  /* Pass 2: M2 = Σ (x - mean)² */
769
1287
  double M2 = 0.0;
770
1288
  ca_size_t __unused_mc = 0;
771
1289
  CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __variancep_bool_P2EXPR, __unused_mc);
772
- op[out_i++] = (double)(M2 / (double)(n_valid));
1290
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid));
773
1291
  }
774
1292
  }
775
1293
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1005
- ca_iter_state st;
1564
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1026,14 +1585,14 @@ variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1026
1585
  op_mask = (boolean8_t *) co->mask->ptr;
1027
1586
  }
1028
1587
  op_mask[out_i] = 1;
1029
- op[out_i++] = (double) 0.0;
1588
+ op[out_i++] = (ca_u_float64_t) 0;
1030
1589
  } else {
1031
1590
  double mean = sum / (double) n_valid;
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);
1036
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
1594
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __variance_i8_P2EXPR, __unused_mc);
1595
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1037
1596
  }
1038
1597
  }
1039
1598
  ca_iter_state_finish(&st);
@@ -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))
1055
- 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)
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
+
1642
+ static VALUE
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
- double *op = (double *) co->ptr;
1062
- ca_iter_state st;
1662
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1083,14 +1683,14 @@ variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1083
1683
  op_mask = (boolean8_t *) co->mask->ptr;
1084
1684
  }
1085
1685
  op_mask[out_i] = 1;
1086
- op[out_i++] = (double) 0.0;
1686
+ op[out_i++] = (ca_u_float64_t) 0;
1087
1687
  } else {
1088
1688
  double mean = sum / (double) n_valid;
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);
1093
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
1692
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __variance_u8_P2EXPR, __unused_mc);
1693
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1094
1694
  }
1095
1695
  }
1096
1696
  ca_iter_state_finish(&st);
@@ -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
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);
1106
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
- double *op = (double *) co->ptr;
1119
- ca_iter_state st;
1760
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -1140,14 +1781,14 @@ variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1140
1781
  op_mask = (boolean8_t *) co->mask->ptr;
1141
1782
  }
1142
1783
  op_mask[out_i] = 1;
1143
- op[out_i++] = (double) 0.0;
1784
+ op[out_i++] = (ca_u_float64_t) 0;
1144
1785
  } else {
1145
1786
  double mean = sum / (double) n_valid;
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(int16_t, double, st, p, m, M2, 0.0, __variance_i16_P2EXPR, __unused_mc);
1150
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
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);
1791
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1151
1792
  }
1152
1793
  }
1153
1794
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1176
- ca_iter_state st;
1858
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -1197,14 +1879,14 @@ variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1197
1879
  op_mask = (boolean8_t *) co->mask->ptr;
1198
1880
  }
1199
1881
  op_mask[out_i] = 1;
1200
- op[out_i++] = (double) 0.0;
1882
+ op[out_i++] = (ca_u_float64_t) 0;
1201
1883
  } else {
1202
1884
  double mean = sum / (double) n_valid;
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(uint16_t, double, st, p, m, M2, 0.0, __variance_u16_P2EXPR, __unused_mc);
1207
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
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);
1889
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1208
1890
  }
1209
1891
  }
1210
1892
  ca_iter_state_finish(&st);
@@ -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
1220
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);
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
- double *op = (double *) co->ptr;
1233
- ca_iter_state st;
1956
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1245,7 +1968,7 @@ variance_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1245
1968
  /* Pass 1: sum = Σx (+ masked_cnt) */
1246
1969
  double sum = 0.0;
1247
1970
  ca_size_t masked_cnt = 0;
1248
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __variance_i32_P1EXPR, masked_cnt);
1971
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, sum, 0.0, __variance_i32_P1EXPR, masked_cnt);
1249
1972
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1250
1973
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1251
1974
  if ( __trigger ) {
@@ -1254,14 +1977,14 @@ variance_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1254
1977
  op_mask = (boolean8_t *) co->mask->ptr;
1255
1978
  }
1256
1979
  op_mask[out_i] = 1;
1257
- op[out_i++] = (double) 0.0;
1980
+ op[out_i++] = (ca_u_float64_t) 0;
1258
1981
  } else {
1259
1982
  double mean = sum / (double) n_valid;
1260
1983
  /* Pass 2: M2 = Σ (x - mean)² */
1261
1984
  double M2 = 0.0;
1262
1985
  ca_size_t __unused_mc = 0;
1263
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __variance_i32_P2EXPR, __unused_mc);
1264
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
1986
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, M2, 0.0, __variance_i32_P2EXPR, __unused_mc);
1987
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1265
1988
  }
1266
1989
  }
1267
1990
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1290
- ca_iter_state st;
2054
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1302,7 +2066,7 @@ variance_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1302
2066
  /* Pass 1: sum = Σx (+ masked_cnt) */
1303
2067
  double sum = 0.0;
1304
2068
  ca_size_t masked_cnt = 0;
1305
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __variance_u32_P1EXPR, masked_cnt);
2069
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, sum, 0.0, __variance_u32_P1EXPR, masked_cnt);
1306
2070
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1307
2071
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1308
2072
  if ( __trigger ) {
@@ -1311,14 +2075,14 @@ variance_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1311
2075
  op_mask = (boolean8_t *) co->mask->ptr;
1312
2076
  }
1313
2077
  op_mask[out_i] = 1;
1314
- op[out_i++] = (double) 0.0;
2078
+ op[out_i++] = (ca_u_float64_t) 0;
1315
2079
  } else {
1316
2080
  double mean = sum / (double) n_valid;
1317
2081
  /* Pass 2: M2 = Σ (x - mean)² */
1318
2082
  double M2 = 0.0;
1319
2083
  ca_size_t __unused_mc = 0;
1320
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __variance_u32_P2EXPR, __unused_mc);
1321
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2084
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, M2, 0.0, __variance_u32_P2EXPR, __unused_mc);
2085
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1322
2086
  }
1323
2087
  }
1324
2088
  ca_iter_state_finish(&st);
@@ -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
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);
1334
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
- double *op = (double *) co->ptr;
1347
- ca_iter_state st;
2152
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1359,7 +2164,7 @@ variance_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1359
2164
  /* Pass 1: sum = Σx (+ masked_cnt) */
1360
2165
  double sum = 0.0;
1361
2166
  ca_size_t masked_cnt = 0;
1362
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __variance_i64_P1EXPR, masked_cnt);
2167
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, sum, 0.0, __variance_i64_P1EXPR, masked_cnt);
1363
2168
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1364
2169
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1365
2170
  if ( __trigger ) {
@@ -1368,14 +2173,14 @@ variance_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1368
2173
  op_mask = (boolean8_t *) co->mask->ptr;
1369
2174
  }
1370
2175
  op_mask[out_i] = 1;
1371
- op[out_i++] = (double) 0.0;
2176
+ op[out_i++] = (ca_u_float64_t) 0;
1372
2177
  } else {
1373
2178
  double mean = sum / (double) n_valid;
1374
2179
  /* Pass 2: M2 = Σ (x - mean)² */
1375
2180
  double M2 = 0.0;
1376
2181
  ca_size_t __unused_mc = 0;
1377
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __variance_i64_P2EXPR, __unused_mc);
1378
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2182
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, M2, 0.0, __variance_i64_P2EXPR, __unused_mc);
2183
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1379
2184
  }
1380
2185
  }
1381
2186
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1404
- ca_iter_state st;
2250
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1416,7 +2262,7 @@ variance_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1416
2262
  /* Pass 1: sum = Σx (+ masked_cnt) */
1417
2263
  double sum = 0.0;
1418
2264
  ca_size_t masked_cnt = 0;
1419
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __variance_u64_P1EXPR, masked_cnt);
2265
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, sum, 0.0, __variance_u64_P1EXPR, masked_cnt);
1420
2266
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1421
2267
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1422
2268
  if ( __trigger ) {
@@ -1425,14 +2271,14 @@ variance_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1425
2271
  op_mask = (boolean8_t *) co->mask->ptr;
1426
2272
  }
1427
2273
  op_mask[out_i] = 1;
1428
- op[out_i++] = (double) 0.0;
2274
+ op[out_i++] = (ca_u_float64_t) 0;
1429
2275
  } else {
1430
2276
  double mean = sum / (double) n_valid;
1431
2277
  /* Pass 2: M2 = Σ (x - mean)² */
1432
2278
  double M2 = 0.0;
1433
2279
  ca_size_t __unused_mc = 0;
1434
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __variance_u64_P2EXPR, __unused_mc);
1435
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2280
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, M2, 0.0, __variance_u64_P2EXPR, __unused_mc);
2281
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1436
2282
  }
1437
2283
  }
1438
2284
  ca_iter_state_finish(&st);
@@ -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
1448
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);
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))
1454
- 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)
1456
- {
1457
- VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
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
+
2328
+ static VALUE
2329
+ variance_ki_native_f32_body (VALUE arg)
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])
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
- double *op = (double *) co->ptr;
1461
- ca_iter_state st;
2348
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1473,7 +2360,7 @@ variance_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1473
2360
  /* Pass 1: sum = Σx (+ masked_cnt) */
1474
2361
  double sum = 0.0;
1475
2362
  ca_size_t masked_cnt = 0;
1476
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __variance_f32_P1EXPR, masked_cnt);
2363
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, sum, 0.0, __variance_f32_P1EXPR, masked_cnt);
1477
2364
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1478
2365
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1479
2366
  if ( __trigger ) {
@@ -1482,14 +2369,14 @@ variance_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1482
2369
  op_mask = (boolean8_t *) co->mask->ptr;
1483
2370
  }
1484
2371
  op_mask[out_i] = 1;
1485
- op[out_i++] = (double) 0.0;
2372
+ op[out_i++] = (ca_u_float64_t) 0;
1486
2373
  } else {
1487
2374
  double mean = sum / (double) n_valid;
1488
2375
  /* Pass 2: M2 = Σ (x - mean)² */
1489
2376
  double M2 = 0.0;
1490
2377
  ca_size_t __unused_mc = 0;
1491
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __variance_f32_P2EXPR, __unused_mc);
1492
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2378
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, M2, 0.0, __variance_f32_P2EXPR, __unused_mc);
2379
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1493
2380
  }
1494
2381
  }
1495
2382
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1518
- ca_iter_state st;
2446
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1530,7 +2458,7 @@ variance_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1530
2458
  /* Pass 1: sum = Σx (+ masked_cnt) */
1531
2459
  double sum = 0.0;
1532
2460
  ca_size_t masked_cnt = 0;
1533
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __variance_f64_P1EXPR, masked_cnt);
2461
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, sum, 0.0, __variance_f64_P1EXPR, masked_cnt);
1534
2462
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1535
2463
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1536
2464
  if ( __trigger ) {
@@ -1539,14 +2467,14 @@ variance_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
1539
2467
  op_mask = (boolean8_t *) co->mask->ptr;
1540
2468
  }
1541
2469
  op_mask[out_i] = 1;
1542
- op[out_i++] = (double) 0.0;
2470
+ op[out_i++] = (ca_u_float64_t) 0;
1543
2471
  } else {
1544
2472
  double mean = sum / (double) n_valid;
1545
2473
  /* Pass 2: M2 = Σ (x - mean)² */
1546
2474
  double M2 = 0.0;
1547
2475
  ca_size_t __unused_mc = 0;
1548
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __variance_f64_P2EXPR, __unused_mc);
1549
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2476
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, M2, 0.0, __variance_f64_P2EXPR, __unused_mc);
2477
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1550
2478
  }
1551
2479
  }
1552
2480
  ca_iter_state_finish(&st);
@@ -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
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);
1562
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
- double *op = (double *) co->ptr;
1575
- ca_iter_state st;
2544
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1585,9 +2554,9 @@ variance_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
1585
2554
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
1586
2555
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
1587
2556
  /* Pass 1: sum = Σx (+ masked_cnt) */
1588
- cmplx64_t sum = 0;
2557
+ ca_u_cmplx64_t sum = 0;
1589
2558
  ca_size_t masked_cnt = 0;
1590
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __variance_cmplx64_P1EXPR, masked_cnt);
2559
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, ca_u_cmplx64_t, st, p, m, sum, 0, __variance_cmplx64_P1EXPR, masked_cnt);
1591
2560
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1592
2561
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1593
2562
  if ( __trigger ) {
@@ -1596,14 +2565,14 @@ variance_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
1596
2565
  op_mask = (boolean8_t *) co->mask->ptr;
1597
2566
  }
1598
2567
  op_mask[out_i] = 1;
1599
- op[out_i++] = (double) 0.0;
2568
+ op[out_i++] = (ca_u_float64_t) 0;
1600
2569
  } else {
1601
- cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
2570
+ ca_u_cmplx64_t mean = sum / (ca_u_cmplx64_t)(double) n_valid;
1602
2571
  /* Pass 2: M2 = Σ (x - mean)² */
1603
2572
  double M2 = 0.0;
1604
2573
  ca_size_t __unused_mc = 0;
1605
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __variance_cmplx64_P2EXPR, __unused_mc);
1606
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2574
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, double, st, p, m, M2, 0.0, __variance_cmplx64_P2EXPR, __unused_mc);
2575
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1607
2576
  }
1608
2577
  }
1609
2578
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1632
- ca_iter_state st;
2642
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1642,9 +2652,9 @@ variance_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t n
1642
2652
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
1643
2653
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
1644
2654
  /* Pass 1: sum = Σx (+ masked_cnt) */
1645
- cmplx128_t sum = 0;
2655
+ ca_u_cmplx128_t sum = 0;
1646
2656
  ca_size_t masked_cnt = 0;
1647
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __variance_cmplx128_P1EXPR, masked_cnt);
2657
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, ca_u_cmplx128_t, st, p, m, sum, 0, __variance_cmplx128_P1EXPR, masked_cnt);
1648
2658
  ca_size_t n_valid = st.slab_elements - masked_cnt;
1649
2659
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
1650
2660
  if ( __trigger ) {
@@ -1653,14 +2663,14 @@ variance_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t n
1653
2663
  op_mask = (boolean8_t *) co->mask->ptr;
1654
2664
  }
1655
2665
  op_mask[out_i] = 1;
1656
- op[out_i++] = (double) 0.0;
2666
+ op[out_i++] = (ca_u_float64_t) 0;
1657
2667
  } else {
1658
- cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
2668
+ ca_u_cmplx128_t mean = sum / (ca_u_cmplx128_t)(double) n_valid;
1659
2669
  /* Pass 2: M2 = Σ (x - mean)² */
1660
2670
  double M2 = 0.0;
1661
2671
  ca_size_t __unused_mc = 0;
1662
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __variance_cmplx128_P2EXPR, __unused_mc);
1663
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2672
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, double, st, p, m, M2, 0.0, __variance_cmplx128_P2EXPR, __unused_mc);
2673
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1664
2674
  }
1665
2675
  }
1666
2676
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1689
- ca_iter_state st;
2740
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1710,14 +2761,14 @@ variance_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes
1710
2761
  op_mask = (boolean8_t *) co->mask->ptr;
1711
2762
  }
1712
2763
  op_mask[out_i] = 1;
1713
- op[out_i++] = (double) 0.0;
2764
+ op[out_i++] = (ca_u_float64_t) 0;
1714
2765
  } else {
1715
2766
  double mean = sum / (double) n_valid;
1716
2767
  /* Pass 2: M2 = Σ (x - mean)² */
1717
2768
  double M2 = 0.0;
1718
2769
  ca_size_t __unused_mc = 0;
1719
2770
  CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __variance_bool_P2EXPR, __unused_mc);
1720
- op[out_i++] = (double)(M2 / (double)(n_valid - 1));
2771
+ op[out_i++] = (ca_u_float64_t)(M2 / (double)(n_valid - 1));
1721
2772
  }
1722
2773
  }
1723
2774
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
1953
- ca_iter_state st;
3045
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -1974,14 +3066,14 @@ stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
1974
3066
  op_mask = (boolean8_t *) co->mask->ptr;
1975
3067
  }
1976
3068
  op_mask[out_i] = 1;
1977
- op[out_i++] = (double) 0.0;
3069
+ op[out_i++] = (ca_u_float64_t) 0;
1978
3070
  } else {
1979
3071
  double mean = sum / (double) n_valid;
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);
1984
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3075
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __stddevp_i8_P2EXPR, __unused_mc);
3076
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
1985
3077
  }
1986
3078
  }
1987
3079
  ca_iter_state_finish(&st);
@@ -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
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);
1997
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
- double *op = (double *) co->ptr;
2010
- ca_iter_state st;
3143
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2031,14 +3164,14 @@ stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
2031
3164
  op_mask = (boolean8_t *) co->mask->ptr;
2032
3165
  }
2033
3166
  op_mask[out_i] = 1;
2034
- op[out_i++] = (double) 0.0;
3167
+ op[out_i++] = (ca_u_float64_t) 0;
2035
3168
  } else {
2036
3169
  double mean = sum / (double) n_valid;
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);
2041
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3173
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __stddevp_u8_P2EXPR, __unused_mc);
3174
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2042
3175
  }
2043
3176
  }
2044
3177
  ca_iter_state_finish(&st);
@@ -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))
2060
- 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)
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
+
3221
+ static VALUE
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
- double *op = (double *) co->ptr;
2067
- ca_iter_state st;
3241
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -2088,14 +3262,14 @@ stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2088
3262
  op_mask = (boolean8_t *) co->mask->ptr;
2089
3263
  }
2090
3264
  op_mask[out_i] = 1;
2091
- op[out_i++] = (double) 0.0;
3265
+ op[out_i++] = (ca_u_float64_t) 0;
2092
3266
  } else {
2093
3267
  double mean = sum / (double) n_valid;
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(int16_t, double, st, p, m, M2, 0.0, __stddevp_i16_P2EXPR, __unused_mc);
2098
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
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);
3272
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2099
3273
  }
2100
3274
  }
2101
3275
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2124
- ca_iter_state st;
3339
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -2145,14 +3360,14 @@ stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2145
3360
  op_mask = (boolean8_t *) co->mask->ptr;
2146
3361
  }
2147
3362
  op_mask[out_i] = 1;
2148
- op[out_i++] = (double) 0.0;
3363
+ op[out_i++] = (ca_u_float64_t) 0;
2149
3364
  } else {
2150
3365
  double mean = sum / (double) n_valid;
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(uint16_t, double, st, p, m, M2, 0.0, __stddevp_u16_P2EXPR, __unused_mc);
2155
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
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);
3370
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2156
3371
  }
2157
3372
  }
2158
3373
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2181
- ca_iter_state st;
3437
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2193,7 +3449,7 @@ stddevp_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2193
3449
  /* Pass 1: sum = Σx (+ masked_cnt) */
2194
3450
  double sum = 0.0;
2195
3451
  ca_size_t masked_cnt = 0;
2196
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __stddevp_i32_P1EXPR, masked_cnt);
3452
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, sum, 0.0, __stddevp_i32_P1EXPR, masked_cnt);
2197
3453
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2198
3454
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2199
3455
  if ( __trigger ) {
@@ -2202,14 +3458,14 @@ stddevp_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2202
3458
  op_mask = (boolean8_t *) co->mask->ptr;
2203
3459
  }
2204
3460
  op_mask[out_i] = 1;
2205
- op[out_i++] = (double) 0.0;
3461
+ op[out_i++] = (ca_u_float64_t) 0;
2206
3462
  } else {
2207
3463
  double mean = sum / (double) n_valid;
2208
3464
  /* Pass 2: M2 = Σ (x - mean)² */
2209
3465
  double M2 = 0.0;
2210
3466
  ca_size_t __unused_mc = 0;
2211
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __stddevp_i32_P2EXPR, __unused_mc);
2212
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3467
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, M2, 0.0, __stddevp_i32_P2EXPR, __unused_mc);
3468
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2213
3469
  }
2214
3470
  }
2215
3471
  ca_iter_state_finish(&st);
@@ -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
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);
2225
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
- double *op = (double *) co->ptr;
2238
- ca_iter_state st;
3535
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2250,7 +3547,7 @@ stddevp_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2250
3547
  /* Pass 1: sum = Σx (+ masked_cnt) */
2251
3548
  double sum = 0.0;
2252
3549
  ca_size_t masked_cnt = 0;
2253
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __stddevp_u32_P1EXPR, masked_cnt);
3550
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, sum, 0.0, __stddevp_u32_P1EXPR, masked_cnt);
2254
3551
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2255
3552
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2256
3553
  if ( __trigger ) {
@@ -2259,14 +3556,14 @@ stddevp_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2259
3556
  op_mask = (boolean8_t *) co->mask->ptr;
2260
3557
  }
2261
3558
  op_mask[out_i] = 1;
2262
- op[out_i++] = (double) 0.0;
3559
+ op[out_i++] = (ca_u_float64_t) 0;
2263
3560
  } else {
2264
3561
  double mean = sum / (double) n_valid;
2265
3562
  /* Pass 2: M2 = Σ (x - mean)² */
2266
3563
  double M2 = 0.0;
2267
3564
  ca_size_t __unused_mc = 0;
2268
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __stddevp_u32_P2EXPR, __unused_mc);
2269
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3565
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, M2, 0.0, __stddevp_u32_P2EXPR, __unused_mc);
3566
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2270
3567
  }
2271
3568
  }
2272
3569
  ca_iter_state_finish(&st);
@@ -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
2282
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);
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
- double *op = (double *) co->ptr;
2295
- ca_iter_state st;
3633
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2307,7 +3645,7 @@ stddevp_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2307
3645
  /* Pass 1: sum = Σx (+ masked_cnt) */
2308
3646
  double sum = 0.0;
2309
3647
  ca_size_t masked_cnt = 0;
2310
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __stddevp_i64_P1EXPR, masked_cnt);
3648
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, sum, 0.0, __stddevp_i64_P1EXPR, masked_cnt);
2311
3649
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2312
3650
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2313
3651
  if ( __trigger ) {
@@ -2316,14 +3654,14 @@ stddevp_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2316
3654
  op_mask = (boolean8_t *) co->mask->ptr;
2317
3655
  }
2318
3656
  op_mask[out_i] = 1;
2319
- op[out_i++] = (double) 0.0;
3657
+ op[out_i++] = (ca_u_float64_t) 0;
2320
3658
  } else {
2321
3659
  double mean = sum / (double) n_valid;
2322
3660
  /* Pass 2: M2 = Σ (x - mean)² */
2323
3661
  double M2 = 0.0;
2324
3662
  ca_size_t __unused_mc = 0;
2325
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __stddevp_i64_P2EXPR, __unused_mc);
2326
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3663
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, M2, 0.0, __stddevp_i64_P2EXPR, __unused_mc);
3664
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2327
3665
  }
2328
3666
  }
2329
3667
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2352
- ca_iter_state st;
3731
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2364,7 +3743,7 @@ stddevp_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2364
3743
  /* Pass 1: sum = Σx (+ masked_cnt) */
2365
3744
  double sum = 0.0;
2366
3745
  ca_size_t masked_cnt = 0;
2367
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __stddevp_u64_P1EXPR, masked_cnt);
3746
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, sum, 0.0, __stddevp_u64_P1EXPR, masked_cnt);
2368
3747
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2369
3748
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2370
3749
  if ( __trigger ) {
@@ -2373,14 +3752,14 @@ stddevp_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2373
3752
  op_mask = (boolean8_t *) co->mask->ptr;
2374
3753
  }
2375
3754
  op_mask[out_i] = 1;
2376
- op[out_i++] = (double) 0.0;
3755
+ op[out_i++] = (ca_u_float64_t) 0;
2377
3756
  } else {
2378
3757
  double mean = sum / (double) n_valid;
2379
3758
  /* Pass 2: M2 = Σ (x - mean)² */
2380
3759
  double M2 = 0.0;
2381
3760
  ca_size_t __unused_mc = 0;
2382
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __stddevp_u64_P2EXPR, __unused_mc);
2383
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3761
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, M2, 0.0, __stddevp_u64_P2EXPR, __unused_mc);
3762
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2384
3763
  }
2385
3764
  }
2386
3765
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2409
- ca_iter_state st;
3829
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2421,7 +3841,7 @@ stddevp_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2421
3841
  /* Pass 1: sum = Σx (+ masked_cnt) */
2422
3842
  double sum = 0.0;
2423
3843
  ca_size_t masked_cnt = 0;
2424
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __stddevp_f32_P1EXPR, masked_cnt);
3844
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, sum, 0.0, __stddevp_f32_P1EXPR, masked_cnt);
2425
3845
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2426
3846
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2427
3847
  if ( __trigger ) {
@@ -2430,14 +3850,14 @@ stddevp_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2430
3850
  op_mask = (boolean8_t *) co->mask->ptr;
2431
3851
  }
2432
3852
  op_mask[out_i] = 1;
2433
- op[out_i++] = (double) 0.0;
3853
+ op[out_i++] = (ca_u_float64_t) 0;
2434
3854
  } else {
2435
3855
  double mean = sum / (double) n_valid;
2436
3856
  /* Pass 2: M2 = Σ (x - mean)² */
2437
3857
  double M2 = 0.0;
2438
3858
  ca_size_t __unused_mc = 0;
2439
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __stddevp_f32_P2EXPR, __unused_mc);
2440
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3859
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, M2, 0.0, __stddevp_f32_P2EXPR, __unused_mc);
3860
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2441
3861
  }
2442
3862
  }
2443
3863
  ca_iter_state_finish(&st);
@@ -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
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);
2453
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
- double *op = (double *) co->ptr;
2466
- ca_iter_state st;
3927
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2478,7 +3939,7 @@ stddevp_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2478
3939
  /* Pass 1: sum = Σx (+ masked_cnt) */
2479
3940
  double sum = 0.0;
2480
3941
  ca_size_t masked_cnt = 0;
2481
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __stddevp_f64_P1EXPR, masked_cnt);
3942
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, sum, 0.0, __stddevp_f64_P1EXPR, masked_cnt);
2482
3943
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2483
3944
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2484
3945
  if ( __trigger ) {
@@ -2487,14 +3948,14 @@ stddevp_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2487
3948
  op_mask = (boolean8_t *) co->mask->ptr;
2488
3949
  }
2489
3950
  op_mask[out_i] = 1;
2490
- op[out_i++] = (double) 0.0;
3951
+ op[out_i++] = (ca_u_float64_t) 0;
2491
3952
  } else {
2492
3953
  double mean = sum / (double) n_valid;
2493
3954
  /* Pass 2: M2 = Σ (x - mean)² */
2494
3955
  double M2 = 0.0;
2495
3956
  ca_size_t __unused_mc = 0;
2496
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __stddevp_f64_P2EXPR, __unused_mc);
2497
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
3957
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, M2, 0.0, __stddevp_f64_P2EXPR, __unused_mc);
3958
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2498
3959
  }
2499
3960
  }
2500
3961
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2523
- ca_iter_state st;
4025
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2533,9 +4035,9 @@ stddevp_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
2533
4035
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
2534
4036
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
2535
4037
  /* Pass 1: sum = Σx (+ masked_cnt) */
2536
- cmplx64_t sum = 0;
4038
+ ca_u_cmplx64_t sum = 0;
2537
4039
  ca_size_t masked_cnt = 0;
2538
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __stddevp_cmplx64_P1EXPR, masked_cnt);
4040
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, ca_u_cmplx64_t, st, p, m, sum, 0, __stddevp_cmplx64_P1EXPR, masked_cnt);
2539
4041
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2540
4042
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2541
4043
  if ( __trigger ) {
@@ -2544,14 +4046,14 @@ stddevp_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
2544
4046
  op_mask = (boolean8_t *) co->mask->ptr;
2545
4047
  }
2546
4048
  op_mask[out_i] = 1;
2547
- op[out_i++] = (double) 0.0;
4049
+ op[out_i++] = (ca_u_float64_t) 0;
2548
4050
  } else {
2549
- cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
4051
+ ca_u_cmplx64_t mean = sum / (ca_u_cmplx64_t)(double) n_valid;
2550
4052
  /* Pass 2: M2 = Σ (x - mean)² */
2551
4053
  double M2 = 0.0;
2552
4054
  ca_size_t __unused_mc = 0;
2553
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __stddevp_cmplx64_P2EXPR, __unused_mc);
2554
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
4055
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, double, st, p, m, M2, 0.0, __stddevp_cmplx64_P2EXPR, __unused_mc);
4056
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2555
4057
  }
2556
4058
  }
2557
4059
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2580
- ca_iter_state st;
4123
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2590,9 +4133,9 @@ stddevp_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
2590
4133
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
2591
4134
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
2592
4135
  /* Pass 1: sum = Σx (+ masked_cnt) */
2593
- cmplx128_t sum = 0;
4136
+ ca_u_cmplx128_t sum = 0;
2594
4137
  ca_size_t masked_cnt = 0;
2595
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __stddevp_cmplx128_P1EXPR, masked_cnt);
4138
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, ca_u_cmplx128_t, st, p, m, sum, 0, __stddevp_cmplx128_P1EXPR, masked_cnt);
2596
4139
  ca_size_t n_valid = st.slab_elements - masked_cnt;
2597
4140
  int __trigger = ca_too_few_present(n_valid, min_count, 1);
2598
4141
  if ( __trigger ) {
@@ -2601,14 +4144,14 @@ stddevp_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t na
2601
4144
  op_mask = (boolean8_t *) co->mask->ptr;
2602
4145
  }
2603
4146
  op_mask[out_i] = 1;
2604
- op[out_i++] = (double) 0.0;
4147
+ op[out_i++] = (ca_u_float64_t) 0;
2605
4148
  } else {
2606
- cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
4149
+ ca_u_cmplx128_t mean = sum / (ca_u_cmplx128_t)(double) n_valid;
2607
4150
  /* Pass 2: M2 = Σ (x - mean)² */
2608
4151
  double M2 = 0.0;
2609
4152
  ca_size_t __unused_mc = 0;
2610
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __stddevp_cmplx128_P2EXPR, __unused_mc);
2611
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
4153
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, double, st, p, m, M2, 0.0, __stddevp_cmplx128_P2EXPR, __unused_mc);
4154
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2612
4155
  }
2613
4156
  }
2614
4157
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2637
- ca_iter_state st;
4221
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2658,14 +4242,14 @@ stddevp_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
2658
4242
  op_mask = (boolean8_t *) co->mask->ptr;
2659
4243
  }
2660
4244
  op_mask[out_i] = 1;
2661
- op[out_i++] = (double) 0.0;
4245
+ op[out_i++] = (ca_u_float64_t) 0;
2662
4246
  } else {
2663
4247
  double mean = sum / (double) n_valid;
2664
4248
  /* Pass 2: M2 = Σ (x - mean)² */
2665
4249
  double M2 = 0.0;
2666
4250
  ca_size_t __unused_mc = 0;
2667
4251
  CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __stddevp_bool_P2EXPR, __unused_mc);
2668
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid)));
4252
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid)));
2669
4253
  }
2670
4254
  }
2671
4255
  ca_iter_state_finish(&st);
@@ -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;
@@ -2715,7 +4314,7 @@ stddevp_ki_native_object_body (VALUE arg)
2715
4314
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
2716
4315
  CArray *co;
2717
4316
  GetCArray(vout, co);
2718
- double *op = (double *) co->ptr;
4317
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
2719
4318
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
2720
4319
  slab_axes, naxes, 0);
2721
4320
  if ( rc != CA_ITER_OK ) {
@@ -2739,7 +4338,7 @@ stddevp_ki_native_object_body (VALUE arg)
2739
4338
  op_mask = (boolean8_t *) co->mask->ptr;
2740
4339
  }
2741
4340
  op_mask[out_i] = 1;
2742
- op[out_i++] = (double) 0.0;
4341
+ op[out_i++] = (ca_u_float64_t) 0;
2743
4342
  } else {
2744
4343
  VALUE mean = rb_funcall(sum, rb_intern("/"), 1, LONG2NUM(n_valid));
2745
4344
  /* Pass 2: M2 = Σ (x - mean)² */
@@ -2747,7 +4346,7 @@ stddevp_ki_native_object_body (VALUE arg)
2747
4346
  ca_size_t __unused_mc = 0;
2748
4347
  CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, M2, INT2FIX(0), VALUE __d = rb_funcall(v, rb_intern("-"), 1, mean);
2749
4348
  M2 = rb_funcall(M2, rb_intern("+"), 1, rb_funcall(__d, rb_intern("*"), 1, __d)), __unused_mc);
2750
- op[out_i++] = (double)(ca_sqrt_clamp(NUM2DBL(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid)))));
4349
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(NUM2DBL(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid)))));
2751
4350
  }
2752
4351
  }
2753
4352
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2901
- ca_iter_state st;
4526
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2922,14 +4547,14 @@ stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2922
4547
  op_mask = (boolean8_t *) co->mask->ptr;
2923
4548
  }
2924
4549
  op_mask[out_i] = 1;
2925
- op[out_i++] = (double) 0.0;
4550
+ op[out_i++] = (ca_u_float64_t) 0;
2926
4551
  } else {
2927
4552
  double mean = sum / (double) n_valid;
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);
2932
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
4556
+ CA_SLAB_REDUCE_M2_NARROW_EX(int8_t, int32_t, st, p, m, M2, 0.0, mean, __stddev_i8_P2EXPR, __unused_mc);
4557
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
2933
4558
  }
2934
4559
  }
2935
4560
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
2958
- ca_iter_state st;
4624
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -2979,14 +4645,14 @@ stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, in
2979
4645
  op_mask = (boolean8_t *) co->mask->ptr;
2980
4646
  }
2981
4647
  op_mask[out_i] = 1;
2982
- op[out_i++] = (double) 0.0;
4648
+ op[out_i++] = (ca_u_float64_t) 0;
2983
4649
  } else {
2984
4650
  double mean = sum / (double) n_valid;
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);
2989
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
4654
+ CA_SLAB_REDUCE_M2_NARROW_EX(uint8_t, int32_t, st, p, m, M2, 0.0, mean, __stddev_u8_P2EXPR, __unused_mc);
4655
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
2990
4656
  }
2991
4657
  }
2992
4658
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3015
- ca_iter_state st;
4722
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -3036,14 +4743,14 @@ stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3036
4743
  op_mask = (boolean8_t *) co->mask->ptr;
3037
4744
  }
3038
4745
  op_mask[out_i] = 1;
3039
- op[out_i++] = (double) 0.0;
4746
+ op[out_i++] = (ca_u_float64_t) 0;
3040
4747
  } else {
3041
4748
  double mean = sum / (double) n_valid;
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(int16_t, double, st, p, m, M2, 0.0, __stddev_i16_P2EXPR, __unused_mc);
3046
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
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);
4753
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3047
4754
  }
3048
4755
  }
3049
4756
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3072
- ca_iter_state st;
4820
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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(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 ) {
@@ -3093,14 +4841,14 @@ stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3093
4841
  op_mask = (boolean8_t *) co->mask->ptr;
3094
4842
  }
3095
4843
  op_mask[out_i] = 1;
3096
- op[out_i++] = (double) 0.0;
4844
+ op[out_i++] = (ca_u_float64_t) 0;
3097
4845
  } else {
3098
4846
  double mean = sum / (double) n_valid;
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(uint16_t, double, st, p, m, M2, 0.0, __stddev_u16_P2EXPR, __unused_mc);
3103
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
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);
4851
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3104
4852
  }
3105
4853
  }
3106
4854
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3129
- ca_iter_state st;
4918
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3141,7 +4930,7 @@ stddev_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3141
4930
  /* Pass 1: sum = Σx (+ masked_cnt) */
3142
4931
  double sum = 0.0;
3143
4932
  ca_size_t masked_cnt = 0;
3144
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __stddev_i32_P1EXPR, masked_cnt);
4933
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, sum, 0.0, __stddev_i32_P1EXPR, masked_cnt);
3145
4934
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3146
4935
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3147
4936
  if ( __trigger ) {
@@ -3150,14 +4939,14 @@ stddev_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3150
4939
  op_mask = (boolean8_t *) co->mask->ptr;
3151
4940
  }
3152
4941
  op_mask[out_i] = 1;
3153
- op[out_i++] = (double) 0.0;
4942
+ op[out_i++] = (ca_u_float64_t) 0;
3154
4943
  } else {
3155
4944
  double mean = sum / (double) n_valid;
3156
4945
  /* Pass 2: M2 = Σ (x - mean)² */
3157
4946
  double M2 = 0.0;
3158
4947
  ca_size_t __unused_mc = 0;
3159
- CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __stddev_i32_P2EXPR, __unused_mc);
3160
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
4948
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int32_t, double, st, p, m, M2, 0.0, __stddev_i32_P2EXPR, __unused_mc);
4949
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3161
4950
  }
3162
4951
  }
3163
4952
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3186
- ca_iter_state st;
5016
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3198,7 +5028,7 @@ stddev_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3198
5028
  /* Pass 1: sum = Σx (+ masked_cnt) */
3199
5029
  double sum = 0.0;
3200
5030
  ca_size_t masked_cnt = 0;
3201
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __stddev_u32_P1EXPR, masked_cnt);
5031
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, sum, 0.0, __stddev_u32_P1EXPR, masked_cnt);
3202
5032
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3203
5033
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3204
5034
  if ( __trigger ) {
@@ -3207,14 +5037,14 @@ stddev_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3207
5037
  op_mask = (boolean8_t *) co->mask->ptr;
3208
5038
  }
3209
5039
  op_mask[out_i] = 1;
3210
- op[out_i++] = (double) 0.0;
5040
+ op[out_i++] = (ca_u_float64_t) 0;
3211
5041
  } else {
3212
5042
  double mean = sum / (double) n_valid;
3213
5043
  /* Pass 2: M2 = Σ (x - mean)² */
3214
5044
  double M2 = 0.0;
3215
5045
  ca_size_t __unused_mc = 0;
3216
- CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __stddev_u32_P2EXPR, __unused_mc);
3217
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5046
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint32_t, double, st, p, m, M2, 0.0, __stddev_u32_P2EXPR, __unused_mc);
5047
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3218
5048
  }
3219
5049
  }
3220
5050
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3243
- ca_iter_state st;
5114
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3255,7 +5126,7 @@ stddev_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3255
5126
  /* Pass 1: sum = Σx (+ masked_cnt) */
3256
5127
  double sum = 0.0;
3257
5128
  ca_size_t masked_cnt = 0;
3258
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __stddev_i64_P1EXPR, masked_cnt);
5129
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, sum, 0.0, __stddev_i64_P1EXPR, masked_cnt);
3259
5130
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3260
5131
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3261
5132
  if ( __trigger ) {
@@ -3264,14 +5135,14 @@ stddev_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3264
5135
  op_mask = (boolean8_t *) co->mask->ptr;
3265
5136
  }
3266
5137
  op_mask[out_i] = 1;
3267
- op[out_i++] = (double) 0.0;
5138
+ op[out_i++] = (ca_u_float64_t) 0;
3268
5139
  } else {
3269
5140
  double mean = sum / (double) n_valid;
3270
5141
  /* Pass 2: M2 = Σ (x - mean)² */
3271
5142
  double M2 = 0.0;
3272
5143
  ca_size_t __unused_mc = 0;
3273
- CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __stddev_i64_P2EXPR, __unused_mc);
3274
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5144
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_int64_t, double, st, p, m, M2, 0.0, __stddev_i64_P2EXPR, __unused_mc);
5145
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3275
5146
  }
3276
5147
  }
3277
5148
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3300
- ca_iter_state st;
5212
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3312,7 +5224,7 @@ stddev_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3312
5224
  /* Pass 1: sum = Σx (+ masked_cnt) */
3313
5225
  double sum = 0.0;
3314
5226
  ca_size_t masked_cnt = 0;
3315
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __stddev_u64_P1EXPR, masked_cnt);
5227
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, sum, 0.0, __stddev_u64_P1EXPR, masked_cnt);
3316
5228
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3317
5229
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3318
5230
  if ( __trigger ) {
@@ -3321,14 +5233,14 @@ stddev_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3321
5233
  op_mask = (boolean8_t *) co->mask->ptr;
3322
5234
  }
3323
5235
  op_mask[out_i] = 1;
3324
- op[out_i++] = (double) 0.0;
5236
+ op[out_i++] = (ca_u_float64_t) 0;
3325
5237
  } else {
3326
5238
  double mean = sum / (double) n_valid;
3327
5239
  /* Pass 2: M2 = Σ (x - mean)² */
3328
5240
  double M2 = 0.0;
3329
5241
  ca_size_t __unused_mc = 0;
3330
- CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __stddev_u64_P2EXPR, __unused_mc);
3331
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5242
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_uint64_t, double, st, p, m, M2, 0.0, __stddev_u64_P2EXPR, __unused_mc);
5243
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3332
5244
  }
3333
5245
  }
3334
5246
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3357
- ca_iter_state st;
5310
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3369,7 +5322,7 @@ stddev_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3369
5322
  /* Pass 1: sum = Σx (+ masked_cnt) */
3370
5323
  double sum = 0.0;
3371
5324
  ca_size_t masked_cnt = 0;
3372
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __stddev_f32_P1EXPR, masked_cnt);
5325
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, sum, 0.0, __stddev_f32_P1EXPR, masked_cnt);
3373
5326
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3374
5327
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3375
5328
  if ( __trigger ) {
@@ -3378,14 +5331,14 @@ stddev_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3378
5331
  op_mask = (boolean8_t *) co->mask->ptr;
3379
5332
  }
3380
5333
  op_mask[out_i] = 1;
3381
- op[out_i++] = (double) 0.0;
5334
+ op[out_i++] = (ca_u_float64_t) 0;
3382
5335
  } else {
3383
5336
  double mean = sum / (double) n_valid;
3384
5337
  /* Pass 2: M2 = Σ (x - mean)² */
3385
5338
  double M2 = 0.0;
3386
5339
  ca_size_t __unused_mc = 0;
3387
- CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __stddev_f32_P2EXPR, __unused_mc);
3388
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5340
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float32_t, double, st, p, m, M2, 0.0, __stddev_f32_P2EXPR, __unused_mc);
5341
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3389
5342
  }
3390
5343
  }
3391
5344
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3414
- ca_iter_state st;
5408
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3426,7 +5420,7 @@ stddev_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3426
5420
  /* Pass 1: sum = Σx (+ masked_cnt) */
3427
5421
  double sum = 0.0;
3428
5422
  ca_size_t masked_cnt = 0;
3429
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __stddev_f64_P1EXPR, masked_cnt);
5423
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, sum, 0.0, __stddev_f64_P1EXPR, masked_cnt);
3430
5424
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3431
5425
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3432
5426
  if ( __trigger ) {
@@ -3435,14 +5429,14 @@ stddev_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, i
3435
5429
  op_mask = (boolean8_t *) co->mask->ptr;
3436
5430
  }
3437
5431
  op_mask[out_i] = 1;
3438
- op[out_i++] = (double) 0.0;
5432
+ op[out_i++] = (ca_u_float64_t) 0;
3439
5433
  } else {
3440
5434
  double mean = sum / (double) n_valid;
3441
5435
  /* Pass 2: M2 = Σ (x - mean)² */
3442
5436
  double M2 = 0.0;
3443
5437
  ca_size_t __unused_mc = 0;
3444
- CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __stddev_f64_P2EXPR, __unused_mc);
3445
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5438
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_float64_t, double, st, p, m, M2, 0.0, __stddev_f64_P2EXPR, __unused_mc);
5439
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3446
5440
  }
3447
5441
  }
3448
5442
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3471
- ca_iter_state st;
5506
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3481,9 +5516,9 @@ stddev_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxe
3481
5516
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
3482
5517
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
3483
5518
  /* Pass 1: sum = Σx (+ masked_cnt) */
3484
- cmplx64_t sum = 0;
5519
+ ca_u_cmplx64_t sum = 0;
3485
5520
  ca_size_t masked_cnt = 0;
3486
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __stddev_cmplx64_P1EXPR, masked_cnt);
5521
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, ca_u_cmplx64_t, st, p, m, sum, 0, __stddev_cmplx64_P1EXPR, masked_cnt);
3487
5522
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3488
5523
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3489
5524
  if ( __trigger ) {
@@ -3492,14 +5527,14 @@ stddev_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxe
3492
5527
  op_mask = (boolean8_t *) co->mask->ptr;
3493
5528
  }
3494
5529
  op_mask[out_i] = 1;
3495
- op[out_i++] = (double) 0.0;
5530
+ op[out_i++] = (ca_u_float64_t) 0;
3496
5531
  } else {
3497
- cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
5532
+ ca_u_cmplx64_t mean = sum / (ca_u_cmplx64_t)(double) n_valid;
3498
5533
  /* Pass 2: M2 = Σ (x - mean)² */
3499
5534
  double M2 = 0.0;
3500
5535
  ca_size_t __unused_mc = 0;
3501
- CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __stddev_cmplx64_P2EXPR, __unused_mc);
3502
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5536
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx64_t, double, st, p, m, M2, 0.0, __stddev_cmplx64_P2EXPR, __unused_mc);
5537
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3503
5538
  }
3504
5539
  }
3505
5540
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3528
- ca_iter_state st;
5604
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3538,9 +5614,9 @@ stddev_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
3538
5614
  boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
3539
5615
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
3540
5616
  /* Pass 1: sum = Σx (+ masked_cnt) */
3541
- cmplx128_t sum = 0;
5617
+ ca_u_cmplx128_t sum = 0;
3542
5618
  ca_size_t masked_cnt = 0;
3543
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __stddev_cmplx128_P1EXPR, masked_cnt);
5619
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, ca_u_cmplx128_t, st, p, m, sum, 0, __stddev_cmplx128_P1EXPR, masked_cnt);
3544
5620
  ca_size_t n_valid = st.slab_elements - masked_cnt;
3545
5621
  int __trigger = ca_too_few_present(n_valid, min_count, 2);
3546
5622
  if ( __trigger ) {
@@ -3549,14 +5625,14 @@ stddev_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t nax
3549
5625
  op_mask = (boolean8_t *) co->mask->ptr;
3550
5626
  }
3551
5627
  op_mask[out_i] = 1;
3552
- op[out_i++] = (double) 0.0;
5628
+ op[out_i++] = (ca_u_float64_t) 0;
3553
5629
  } else {
3554
- cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
5630
+ ca_u_cmplx128_t mean = sum / (ca_u_cmplx128_t)(double) n_valid;
3555
5631
  /* Pass 2: M2 = Σ (x - mean)² */
3556
5632
  double M2 = 0.0;
3557
5633
  ca_size_t __unused_mc = 0;
3558
- CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __stddev_cmplx128_P2EXPR, __unused_mc);
3559
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5634
+ CA_SLAB_REDUCE_SUM8_EX(ca_u_cmplx128_t, double, st, p, m, M2, 0.0, __stddev_cmplx128_P2EXPR, __unused_mc);
5635
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3560
5636
  }
3561
5637
  }
3562
5638
  ca_iter_state_finish(&st);
@@ -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
- double *op = (double *) co->ptr;
3585
- ca_iter_state st;
5702
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
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 ) {
@@ -3606,14 +5723,14 @@ stddev_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes,
3606
5723
  op_mask = (boolean8_t *) co->mask->ptr;
3607
5724
  }
3608
5725
  op_mask[out_i] = 1;
3609
- op[out_i++] = (double) 0.0;
5726
+ op[out_i++] = (ca_u_float64_t) 0;
3610
5727
  } else {
3611
5728
  double mean = sum / (double) n_valid;
3612
5729
  /* Pass 2: M2 = Σ (x - mean)² */
3613
5730
  double M2 = 0.0;
3614
5731
  ca_size_t __unused_mc = 0;
3615
5732
  CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __stddev_bool_P2EXPR, __unused_mc);
3616
- op[out_i++] = (double)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
5733
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(M2 / (double)(n_valid - 1)));
3617
5734
  }
3618
5735
  }
3619
5736
  ca_iter_state_finish(&st);
@@ -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;
@@ -3663,7 +5795,7 @@ stddev_ki_native_object_body (VALUE arg)
3663
5795
  VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
3664
5796
  CArray *co;
3665
5797
  GetCArray(vout, co);
3666
- double *op = (double *) co->ptr;
5798
+ ca_u_float64_t *op = (ca_u_float64_t *) co->ptr;
3667
5799
  int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
3668
5800
  slab_axes, naxes, 0);
3669
5801
  if ( rc != CA_ITER_OK ) {
@@ -3687,7 +5819,7 @@ stddev_ki_native_object_body (VALUE arg)
3687
5819
  op_mask = (boolean8_t *) co->mask->ptr;
3688
5820
  }
3689
5821
  op_mask[out_i] = 1;
3690
- op[out_i++] = (double) 0.0;
5822
+ op[out_i++] = (ca_u_float64_t) 0;
3691
5823
  } else {
3692
5824
  VALUE mean = rb_funcall(sum, rb_intern("/"), 1, LONG2NUM(n_valid));
3693
5825
  /* Pass 2: M2 = Σ (x - mean)² */
@@ -3695,7 +5827,7 @@ stddev_ki_native_object_body (VALUE arg)
3695
5827
  ca_size_t __unused_mc = 0;
3696
5828
  CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, M2, INT2FIX(0), VALUE __d = rb_funcall(v, rb_intern("-"), 1, mean);
3697
5829
  M2 = rb_funcall(M2, rb_intern("+"), 1, rb_funcall(__d, rb_intern("*"), 1, __d)), __unused_mc);
3698
- op[out_i++] = (double)(ca_sqrt_clamp(NUM2DBL(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid - 1)))));
5830
+ op[out_i++] = (ca_u_float64_t)(ca_sqrt_clamp(NUM2DBL(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid - 1)))));
3699
5831
  }
3700
5832
  }
3701
5833
  ca_iter_state_finish(&st);
@@ -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