carray 3.0.1 → 3.0.2

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +520 -0
  3. data/README.md +2 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +33 -4
  6. data/ext/ca_axis_group.c +202 -96
  7. data/ext/ca_categorical_iterator.c +108 -54
  8. data/ext/ca_kernel_iterator.c +317 -51
  9. data/ext/ca_kernel_iterator.h +142 -35
  10. data/ext/ca_obj_array.c +62 -20
  11. data/ext/ca_obj_block.c +4 -4
  12. data/ext/ca_obj_const_string.c +85 -26
  13. data/ext/ca_obj_face.c +24 -0
  14. data/ext/ca_obj_face.h +15 -0
  15. data/ext/ca_obj_fixlen_string.c +18 -5
  16. data/ext/ca_obj_meld.c +123 -25
  17. data/ext/ca_obj_object.c +8 -0
  18. data/ext/ca_obj_select.c +49 -34
  19. data/ext/ca_obj_stack.c +3 -8
  20. data/ext/ca_obj_stride.c +72 -1
  21. data/ext/ca_obj_string.c +8 -4
  22. data/ext/ca_obj_window.c +8 -2
  23. data/ext/ca_op_ipower.c +1 -2
  24. data/ext/ca_rng_normal.h +42 -0
  25. data/ext/ca_rng_xoshiro256pp.h +105 -0
  26. data/ext/ca_sweep_engine.c +307 -143
  27. data/ext/ca_sweep_engine.h +26 -5
  28. data/ext/carray.h +21 -2
  29. data/ext/carray_access.c +32 -20
  30. data/ext/carray_address_basis.c +590 -0
  31. data/ext/carray_broadcast.c +3 -3
  32. data/ext/carray_call_cfunc.c +667 -483
  33. data/ext/carray_cast.c +115 -41
  34. data/ext/carray_copy.c +55 -30
  35. data/ext/carray_core.c +83 -3
  36. data/ext/carray_count.c +9 -10
  37. data/ext/carray_factorize.c +46 -25
  38. data/ext/carray_internal.h +17 -0
  39. data/ext/carray_kernels_reduce_aggregate.c +168 -0
  40. data/ext/carray_kernels_reduce_cumulative.c +270 -1
  41. data/ext/carray_kernels_reduce_extreme.c +554 -8
  42. data/ext/carray_kernels_scan.c +4 -4
  43. data/ext/carray_kernels_search.c +94 -14
  44. data/ext/carray_loop.c +7 -1
  45. data/ext/carray_mask.c +23 -8
  46. data/ext/carray_median_percentile.c +55 -0
  47. data/ext/carray_operator.c +4 -4
  48. data/ext/carray_order.c +1 -1
  49. data/ext/carray_random.c +384 -40
  50. data/ext/carray_slab.c +13 -0
  51. data/ext/carray_sort.c +20 -22
  52. data/ext/mk_call_cfunc.rb +103 -116
  53. data/ext/mkkernel.rb +297 -29
  54. data/ext/ruby_carray.c +10 -1
  55. data/ext/version.h +4 -4
  56. data/lib/carray/autoload_carray.rb +5 -3
  57. data/lib/carray/autoload_method_extension.rb +12 -0
  58. data/lib/carray/axis_group.rb +77 -0
  59. data/lib/carray/basics.rb +4 -0
  60. data/lib/carray/block_iterator.rb +92 -16
  61. data/lib/carray/categorical.rb +150 -33
  62. data/lib/carray/categorical_iterator.rb +207 -80
  63. data/lib/carray/const_string.rb +131 -27
  64. data/lib/carray/construct.rb +40 -0
  65. data/lib/carray/data_type_extension.rb +3 -0
  66. data/lib/carray/data_type_limits.rb +91 -0
  67. data/lib/carray/fixlen_string.rb +1 -1
  68. data/lib/carray/frame/csv_parser.rb +11 -4
  69. data/lib/carray/frame/frame.rb +81 -10
  70. data/lib/carray/frame/group.rb +36 -3
  71. data/lib/carray/frame/io.rb +67 -15
  72. data/lib/carray/frame/records.rb +18 -4
  73. data/lib/carray/frame/verbs.rb +14 -11
  74. data/lib/carray/inspect.rb +42 -9
  75. data/lib/carray/iterator.rb +143 -0
  76. data/lib/carray/lazy.rb +0 -37
  77. data/lib/carray/mask_gap_fill.rb +3 -1
  78. data/lib/carray/methods/discovery_along.rb +74 -0
  79. data/lib/carray/methods/factorize.rb +50 -0
  80. data/lib/carray/methods/is_in.rb +13 -2
  81. data/lib/carray/methods/locate_addr.rb +75 -2
  82. data/lib/carray/methods/mask_duplicates.rb +35 -1
  83. data/lib/carray/methods/nunique.rb +22 -1
  84. data/lib/carray/methods/repeat.rb +110 -0
  85. data/lib/carray/methods/unique.rb +41 -1
  86. data/lib/carray/rng.rb +86 -0
  87. data/lib/carray/slab_iterator.rb +58 -13
  88. data/lib/carray/string_operation_extension.rb +5 -1
  89. data/lib/carray/time.rb +18 -2
  90. data/lib/carray/window_iterator.rb +142 -20
  91. data/lib/carray.rb +2 -0
  92. data/yard-stubs/ca_obj_block.rb +2 -7
  93. data/yard-stubs/ca_obj_window.rb +10 -2
  94. data/yard-stubs/carray_access.rb +1 -1
  95. data/yard-stubs/carray_broadcast.rb +1 -1
  96. data/yard-stubs/carray_core.rb +0 -80
  97. data/yard-stubs/carray_count.rb +7 -2
  98. data/yard-stubs/carray_lazy.rb +205 -0
  99. data/yard-stubs/carray_math.rb +1486 -3
  100. data/yard-stubs/carray_median_percentile.rb +16 -2
  101. data/yard-stubs/carray_order.rb +9 -69
  102. data/yard-stubs/carray_slab.rb +9 -7
  103. data/yard-stubs/carray_sort.rb +7 -5
  104. metadata +9 -1
@@ -138,7 +138,20 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
138
138
 
139
139
  --------------------------------------------------------------------------- */
140
140
 
141
- #define REDUCEAT_MOMENTS_BODY(T) \
141
+ /* NaN loses every contest, which is what CArray#min / #max do (mkkernel
142
+ declares it as `all_nan_result: :nan`): a NaN never displaces a number, the
143
+ first number displaces a NaN that seeded the accumulator, and a segment
144
+ holding nothing but NaN answers NaN. Without this the answer depends on
145
+ where in the segment the NaN sits, and a reduction that is order-free
146
+ stopped being order-free.
147
+
148
+ The predicate is passed per instantiation rather than written inline so an
149
+ integer body never compares a value with itself, which is a tautology the
150
+ compiler is right to warn about. */
151
+ #define CAT_NAN_NEVER(v) (0)
152
+ #define CAT_NAN_CHECK(v) ((v) != (v))
153
+
154
+ #define REDUCEAT_MOMENTS_BODY(T, ISNAN) \
142
155
  do { \
143
156
  const T *gp = (const T *) grouped->ptr; \
144
157
  T *minv = (T *) minp, *maxv = (T *) maxp; \
@@ -147,13 +160,17 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
147
160
  ca_size_t hi = (c + 1 < k) ? (ca_size_t) offs[c+1] : n; \
148
161
  ca_size_t j, cnt = 0; \
149
162
  double sacc = 0.0; \
150
- T mn = 0, mx = 0; int seen = 0; \
163
+ T mn = 0, mx = 0; int seen = 0, seen_num = 0; \
151
164
  for ( j = lo; j < hi; j++ ) { \
152
165
  if ( gm && gm[j] ) continue; /* masked value cell */ \
153
166
  { T v = gp[j]; \
154
167
  sacc += (double) v; \
155
- if ( ! seen ) { mn = v; mx = v; seen = 1; } \
156
- else { if ( v < mn ) mn = v; if ( v > mx ) mx = v; } \
168
+ if ( ! ISNAN(v) ) { \
169
+ if ( ! seen_num ) { mn = v; mx = v; seen_num = 1; } \
170
+ else { if ( v < mn ) mn = v; if ( v > mx ) mx = v; } \
171
+ } \
172
+ else if ( ! seen ) { mn = v; mx = v; } /* held until a number lands */\
173
+ seen = 1; \
157
174
  cnt++; } \
158
175
  } \
159
176
  countp[c] = (int64_t) cnt; \
@@ -205,16 +222,16 @@ rb_ca_reduceat_moments (VALUE self, VALUE roffsets, VALUE rcounts,
205
222
  maxm = (boolean8_t *) maxs->mask->ptr;
206
223
 
207
224
  switch ( grouped->data_type ) {
208
- case CA_INT8: REDUCEAT_MOMENTS_BODY(int8_t); break;
209
- case CA_UINT8: REDUCEAT_MOMENTS_BODY(uint8_t); break;
210
- case CA_INT16: REDUCEAT_MOMENTS_BODY(int16_t); break;
211
- case CA_UINT16: REDUCEAT_MOMENTS_BODY(uint16_t); break;
212
- case CA_INT32: REDUCEAT_MOMENTS_BODY(int32_t); break;
213
- case CA_UINT32: REDUCEAT_MOMENTS_BODY(uint32_t); break;
214
- case CA_INT64: REDUCEAT_MOMENTS_BODY(int64_t); break;
215
- case CA_UINT64: REDUCEAT_MOMENTS_BODY(uint64_t); break;
216
- case CA_FLOAT32: REDUCEAT_MOMENTS_BODY(float32_t); break;
217
- case CA_FLOAT64: REDUCEAT_MOMENTS_BODY(float64_t); break;
225
+ case CA_INT8: REDUCEAT_MOMENTS_BODY(int8_t, CAT_NAN_NEVER); break;
226
+ case CA_UINT8: REDUCEAT_MOMENTS_BODY(uint8_t, CAT_NAN_NEVER); break;
227
+ case CA_INT16: REDUCEAT_MOMENTS_BODY(int16_t, CAT_NAN_NEVER); break;
228
+ case CA_UINT16: REDUCEAT_MOMENTS_BODY(uint16_t, CAT_NAN_NEVER); break;
229
+ case CA_INT32: REDUCEAT_MOMENTS_BODY(int32_t, CAT_NAN_NEVER); break;
230
+ case CA_UINT32: REDUCEAT_MOMENTS_BODY(uint32_t, CAT_NAN_NEVER); break;
231
+ case CA_INT64: REDUCEAT_MOMENTS_BODY(int64_t, CAT_NAN_NEVER); break;
232
+ case CA_UINT64: REDUCEAT_MOMENTS_BODY(uint64_t, CAT_NAN_NEVER); break;
233
+ case CA_FLOAT32: REDUCEAT_MOMENTS_BODY(float32_t, CAT_NAN_CHECK); break;
234
+ case CA_FLOAT64: REDUCEAT_MOMENTS_BODY(float64_t, CAT_NAN_CHECK); break;
218
235
  default:
219
236
  rb_raise(rb_eCADataTypeError,
220
237
  "__reduceat_moments__: numeric value required (got data_type %d)",
@@ -278,11 +295,27 @@ ca_nth_element_double (double *a, ca_size_t n, ca_size_t kth)
278
295
  { double f = (double) (m - 1) * p / 100.0; \
279
296
  ca_size_t ki = (ca_size_t) floor(f); \
280
297
  double vlo, vhi; \
281
- ca_nth_element_double(scratch, m, ki); /* scratch[ki] = ki-th */ \
282
- vlo = scratch[ki]; \
283
- if ( ki + 1 < m ) { /* (ki+1)-th = min of upper partition */ \
298
+ /* Push NaN to the tail, which is where CArray's sort puts it, so the \
299
+ ki-th element here is the ki-th of the sorted segment. Selection \
300
+ runs on the numeric prefix, since a comparison-based quickselect \
301
+ has nothing to say about a NaN, and a position landing in the tail \
302
+ answers NaN. The upper neighbour is clamped into the prefix too: a \
303
+ position whose neighbour would be a NaN interpolates against itself \
304
+ and answers vlo, which is why the median of [NaN, -9.0] is -9.0. */ \
305
+ ca_size_t nnum = m, t0 = 0; \
306
+ while ( t0 < nnum ) { \
307
+ if ( scratch[t0] != scratch[t0] ) { \
308
+ double tmp = scratch[--nnum]; \
309
+ scratch[nnum] = scratch[t0]; scratch[t0] = tmp; \
310
+ } else t0++; \
311
+ } \
312
+ if ( ki < nnum ) { \
313
+ ca_nth_element_double(scratch, nnum, ki); /* scratch[ki] = ki-th */ \
314
+ vlo = scratch[ki]; \
315
+ } else vlo = (double) NAN; \
316
+ if ( ki + 1 < nnum ) { /* (ki+1)-th = min of upper partition */ \
284
317
  double mn = scratch[ki+1]; ca_size_t t; \
285
- for ( t = ki + 2; t < m; t++ ) if ( scratch[t] < mn ) mn = scratch[t]; \
318
+ for ( t = ki + 2; t < nnum; t++ ) if ( scratch[t] < mn ) mn = scratch[t]; \
286
319
  vhi = mn; \
287
320
  } else vhi = vlo; \
288
321
  outp[c] = vlo + (f - (double) ki) * (vhi - vlo); } \
@@ -510,7 +543,7 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
510
543
  /* __reduceat_argminmax__(offsets, min_idx, max_idx) — per-segment GROUP-LOCAL
511
544
  index of the min / max (position within the segment, first occurrence on
512
545
  ties). Empty / all-masked segments are masked. */
513
- #define REDUCEAT_ARGMINMAX_BODY(T) \
546
+ #define REDUCEAT_ARGMINMAX_BODY(T, ISNAN) \
514
547
  do { \
515
548
  const T *gp = (const T *) grouped->ptr; \
516
549
  for ( c = 0; c < k; c++ ) { \
@@ -520,10 +553,13 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
520
553
  for ( j = lo; j < hi; j++ ) { \
521
554
  if ( gm && gm[j] ) continue; \
522
555
  { T v = gp[j]; ca_size_t li = j - lo; \
556
+ if ( ISNAN(v) ) continue; /* wins no contest, so marks no position */\
523
557
  if ( ! seen ) { mn = mx = v; mni = mxi = li; seen = 1; } \
524
558
  else { if ( v < mn ) { mn = v; mni = li; } \
525
559
  if ( v > mx ) { mx = v; mxi = li; } } } \
526
560
  } \
561
+ /* A segment of nothing but NaN has no position to report, the same as a \
562
+ segment with no present cell at all -- both are UNDEF, as in the core.*/\
527
563
  if ( seen ) { minp[c] = (int64_t) mni; maxp[c] = (int64_t) mxi; } \
528
564
  else { minp[c] = 0; maxp[c] = 0; minm[c] = 1; maxm[c] = 1; } \
529
565
  } \
@@ -558,16 +594,16 @@ rb_ca_reduceat_argminmax (VALUE self, VALUE roffsets, VALUE rminidx, VALUE rmaxi
558
594
  maxm = (boolean8_t *) maxidx->mask->ptr;
559
595
 
560
596
  switch ( grouped->data_type ) {
561
- case CA_INT8: REDUCEAT_ARGMINMAX_BODY(int8_t); break;
562
- case CA_UINT8: REDUCEAT_ARGMINMAX_BODY(uint8_t); break;
563
- case CA_INT16: REDUCEAT_ARGMINMAX_BODY(int16_t); break;
564
- case CA_UINT16: REDUCEAT_ARGMINMAX_BODY(uint16_t); break;
565
- case CA_INT32: REDUCEAT_ARGMINMAX_BODY(int32_t); break;
566
- case CA_UINT32: REDUCEAT_ARGMINMAX_BODY(uint32_t); break;
567
- case CA_INT64: REDUCEAT_ARGMINMAX_BODY(int64_t); break;
568
- case CA_UINT64: REDUCEAT_ARGMINMAX_BODY(uint64_t); break;
569
- case CA_FLOAT32: REDUCEAT_ARGMINMAX_BODY(float32_t); break;
570
- case CA_FLOAT64: REDUCEAT_ARGMINMAX_BODY(float64_t); break;
597
+ case CA_INT8: REDUCEAT_ARGMINMAX_BODY(int8_t, CAT_NAN_NEVER); break;
598
+ case CA_UINT8: REDUCEAT_ARGMINMAX_BODY(uint8_t, CAT_NAN_NEVER); break;
599
+ case CA_INT16: REDUCEAT_ARGMINMAX_BODY(int16_t, CAT_NAN_NEVER); break;
600
+ case CA_UINT16: REDUCEAT_ARGMINMAX_BODY(uint16_t, CAT_NAN_NEVER); break;
601
+ case CA_INT32: REDUCEAT_ARGMINMAX_BODY(int32_t, CAT_NAN_NEVER); break;
602
+ case CA_UINT32: REDUCEAT_ARGMINMAX_BODY(uint32_t, CAT_NAN_NEVER); break;
603
+ case CA_INT64: REDUCEAT_ARGMINMAX_BODY(int64_t, CAT_NAN_NEVER); break;
604
+ case CA_UINT64: REDUCEAT_ARGMINMAX_BODY(uint64_t, CAT_NAN_NEVER); break;
605
+ case CA_FLOAT32: REDUCEAT_ARGMINMAX_BODY(float32_t, CAT_NAN_CHECK); break;
606
+ case CA_FLOAT64: REDUCEAT_ARGMINMAX_BODY(float64_t, CAT_NAN_CHECK); break;
571
607
  default:
572
608
  rb_raise(rb_eCADataTypeError,
573
609
  "__reduceat_argminmax__: numeric value required (got data_type %d)",
@@ -631,6 +667,12 @@ static int
631
667
  cmp_double (const void *a, const void *b)
632
668
  {
633
669
  double x = *(const double *) a, y = *(const double *) b;
670
+ /* NaN sorts last, which is where CArray's own sort puts it, so picking a
671
+ position out of the sorted segment gives the core's answer. A bare
672
+ < / > comparison returns 0 for every pair involving a NaN, which is not
673
+ a strict weak ordering and leaves qsort free to produce anything. */
674
+ if ( x != x ) return (y != y) ? 0 : 1;
675
+ if ( y != y ) return -1;
634
676
  return (x < y) ? -1 : (x > y) ? 1 : 0;
635
677
  }
636
678
 
@@ -648,13 +690,18 @@ cmp_double (const void *a, const void *b)
648
690
  } \
649
691
  if ( m == 0 ) { for ( t = 0; t < 5; t++ ) { outp[t][c] = 0.0; outm[t][c] = 1; } continue; } \
650
692
  qsort(scratch, (size_t) m, sizeof(double), cmp_double); \
693
+ { ca_size_t nnum = m; \
694
+ while ( nnum > 0 && scratch[nnum-1] != scratch[nnum-1] ) nnum--; \
651
695
  for ( t = 0; t < 5; t++ ) { \
652
696
  double f = (double) (m - 1) * P[t] / 100.0; \
653
697
  ca_size_t ki = (ca_size_t) floor(f); \
654
698
  double vlo = scratch[ki]; \
655
- double vhi = (ki + 1 < m) ? scratch[ki+1] : vlo; \
699
+ /* Clamp the upper neighbour into the numeric prefix: with NaN sorted \
700
+ last, a position whose neighbour is a NaN interpolates against \
701
+ itself, which is what the core answers. */ \
702
+ double vhi = (ki + 1 < nnum) ? scratch[ki+1] : vlo; \
656
703
  outp[t][c] = vlo + (f - (double) ki) * (vhi - vlo); \
657
- } \
704
+ } } \
658
705
  } \
659
706
  } while (0)
660
707
 
@@ -822,7 +869,7 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
822
869
  (empty group cell → 0 + masked, matching __reduceat_moments__).
823
870
  --------------------------------------------------------------------------- */
824
871
 
825
- #define FIBER_SCATTER_BODY(H_T, C_T) \
872
+ #define FIBER_SCATTER_BODY(H_T, C_T, ISNAN) \
826
873
  do { \
827
874
  const H_T *hp = (const H_T *) h->ptr; \
828
875
  const C_T *cp = (const C_T *) codes->ptr; \
@@ -844,11 +891,18 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
844
891
  if ( c < 0 || c >= K ) continue; /* out-of-vocabulary */ \
845
892
  out_off = c * band_size + out_outer + inn; \
846
893
  v = hp[off]; \
894
+ /* NaN loses every contest, as in the flat twin and the core. min \
895
+ and max are seeded together and only ever move on a number, so a \
896
+ NaN sitting in min means this cell has met nothing but NaN yet. */\
847
897
  if ( countp[out_off] == 0 ) { \
848
898
  minv[out_off] = v; maxv[out_off] = v; \
849
- } else { \
850
- if ( v < minv[out_off] ) minv[out_off] = v; \
851
- if ( v > maxv[out_off] ) maxv[out_off] = v; \
899
+ } else if ( ! ISNAN(v) ) { \
900
+ if ( ISNAN(minv[out_off]) ) { \
901
+ minv[out_off] = v; maxv[out_off] = v; \
902
+ } else { \
903
+ if ( v < minv[out_off] ) minv[out_off] = v; \
904
+ if ( v > maxv[out_off] ) maxv[out_off] = v; \
905
+ } \
852
906
  } \
853
907
  countp[out_off]++; \
854
908
  sump[out_off] += (double) v; \
@@ -857,16 +911,16 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
857
911
  } \
858
912
  } while (0)
859
913
 
860
- #define FIBER_SCATTER_DISPATCH_C(H_T) \
914
+ #define FIBER_SCATTER_DISPATCH_C(H_T, ISNAN) \
861
915
  switch ( codes->data_type ) { \
862
- case CA_INT8: FIBER_SCATTER_BODY(H_T, int8_t); break; \
863
- case CA_UINT8: FIBER_SCATTER_BODY(H_T, uint8_t); break; \
864
- case CA_INT16: FIBER_SCATTER_BODY(H_T, int16_t); break; \
865
- case CA_UINT16: FIBER_SCATTER_BODY(H_T, uint16_t); break; \
866
- case CA_INT32: FIBER_SCATTER_BODY(H_T, int32_t); break; \
867
- case CA_UINT32: FIBER_SCATTER_BODY(H_T, uint32_t); break; \
868
- case CA_INT64: FIBER_SCATTER_BODY(H_T, int64_t); break; \
869
- case CA_UINT64: FIBER_SCATTER_BODY(H_T, uint64_t); break; \
916
+ case CA_INT8: FIBER_SCATTER_BODY(H_T, int8_t, ISNAN); break; \
917
+ case CA_UINT8: FIBER_SCATTER_BODY(H_T, uint8_t, ISNAN); break; \
918
+ case CA_INT16: FIBER_SCATTER_BODY(H_T, int16_t, ISNAN); break; \
919
+ case CA_UINT16: FIBER_SCATTER_BODY(H_T, uint16_t, ISNAN); break; \
920
+ case CA_INT32: FIBER_SCATTER_BODY(H_T, int32_t, ISNAN); break; \
921
+ case CA_UINT32: FIBER_SCATTER_BODY(H_T, uint32_t, ISNAN); break; \
922
+ case CA_INT64: FIBER_SCATTER_BODY(H_T, int64_t, ISNAN); break; \
923
+ case CA_UINT64: FIBER_SCATTER_BODY(H_T, uint64_t, ISNAN); break; \
870
924
  default: \
871
925
  ca_detach(h); ca_detach(codes); \
872
926
  rb_raise(rb_eCADataTypeError, \
@@ -966,16 +1020,16 @@ rb_ca_fiber_scatter_moments (VALUE self, VALUE rcodes, VALUE raxis, VALUE rk,
966
1020
  memset(maxp, 0, (size_t) total * (size_t) h->bytes);
967
1021
 
968
1022
  switch ( h->data_type ) {
969
- case CA_INT8: FIBER_SCATTER_DISPATCH_C(int8_t); break;
970
- case CA_UINT8: FIBER_SCATTER_DISPATCH_C(uint8_t); break;
971
- case CA_INT16: FIBER_SCATTER_DISPATCH_C(int16_t); break;
972
- case CA_UINT16: FIBER_SCATTER_DISPATCH_C(uint16_t); break;
973
- case CA_INT32: FIBER_SCATTER_DISPATCH_C(int32_t); break;
974
- case CA_UINT32: FIBER_SCATTER_DISPATCH_C(uint32_t); break;
975
- case CA_INT64: FIBER_SCATTER_DISPATCH_C(int64_t); break;
976
- case CA_UINT64: FIBER_SCATTER_DISPATCH_C(uint64_t); break;
977
- case CA_FLOAT32: FIBER_SCATTER_DISPATCH_C(float32_t); break;
978
- case CA_FLOAT64: FIBER_SCATTER_DISPATCH_C(float64_t); break;
1023
+ case CA_INT8: FIBER_SCATTER_DISPATCH_C(int8_t, CAT_NAN_NEVER); break;
1024
+ case CA_UINT8: FIBER_SCATTER_DISPATCH_C(uint8_t, CAT_NAN_NEVER); break;
1025
+ case CA_INT16: FIBER_SCATTER_DISPATCH_C(int16_t, CAT_NAN_NEVER); break;
1026
+ case CA_UINT16: FIBER_SCATTER_DISPATCH_C(uint16_t, CAT_NAN_NEVER); break;
1027
+ case CA_INT32: FIBER_SCATTER_DISPATCH_C(int32_t, CAT_NAN_NEVER); break;
1028
+ case CA_UINT32: FIBER_SCATTER_DISPATCH_C(uint32_t, CAT_NAN_NEVER); break;
1029
+ case CA_INT64: FIBER_SCATTER_DISPATCH_C(int64_t, CAT_NAN_NEVER); break;
1030
+ case CA_UINT64: FIBER_SCATTER_DISPATCH_C(uint64_t, CAT_NAN_NEVER); break;
1031
+ case CA_FLOAT32: FIBER_SCATTER_DISPATCH_C(float32_t, CAT_NAN_CHECK); break;
1032
+ case CA_FLOAT64: FIBER_SCATTER_DISPATCH_C(float64_t, CAT_NAN_CHECK); break;
979
1033
  default:
980
1034
  ca_detach(h); ca_detach(codes);
981
1035
  rb_raise(rb_eCADataTypeError,