carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
@@ -0,0 +1,273 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ CArray#round(ndigits) and #round!(ndigits): each element rounded as Ruby's
4
+ Float#round(ndigits) and Integer#round(ndigits) round it, half away from
5
+ zero. The argument-free forms are the generated monop kernels; this file
6
+ takes over the method and hands them the calls without an argument.
7
+
8
+ ---------------------------------------------------------------------------- */
9
+
10
+ #include <math.h>
11
+ #include <float.h>
12
+
13
+ #include "carray.h"
14
+ #include "carray_internal.h"
15
+ #include "ca_obj_face.h"
16
+
17
+ VALUE rb_ca_round (VALUE self); /* generated: round without digits */
18
+ VALUE rb_ca_round_bang (VALUE self);
19
+
20
+ static ID id_round;
21
+
22
+ /* The rounding of Float#round for ndigits > 0 (numeric.c, round_half_up
23
+ with its check for a product that came out one short). */
24
+ static double
25
+ ca_round_half_up (double x, double s)
26
+ {
27
+ double f, xs = x * s;
28
+
29
+ f = round(xs);
30
+ if ( x > 0 ) {
31
+ if ( (double)((f + 0.5) / s) <= x ) f += 1;
32
+ x = f;
33
+ }
34
+ else {
35
+ if ( (double)((f - 0.5) / s) >= x ) f -= 1;
36
+ x = f;
37
+ }
38
+ return x;
39
+ }
40
+
41
+ /* numeric.c: float_round_overflow / float_round_underflow. When the first
42
+ holds, number * 10**ndigits is already an integer and the number is its
43
+ own answer; when the second holds, the answer is 0. */
44
+ static int
45
+ ca_round_overflow (long ndigits, int binexp)
46
+ {
47
+ enum { float_dig = DBL_DIG + 2 };
48
+ return ndigits >= float_dig - (binexp > 0 ? binexp / 4 : binexp / 3 - 1);
49
+ }
50
+
51
+ static int
52
+ ca_round_underflow (long ndigits, int binexp)
53
+ {
54
+ return ndigits < - (binexp > 0 ? binexp / 3 + 1 : binexp / 4);
55
+ }
56
+
57
+ /* An integer |x| rounded to a multiple of 10**k (k >= 1), half away from
58
+ zero, as Integer#round(-k). Returns 0 when the answer does not fit in
59
+ 64 bits, and sets *overflow. */
60
+ static uint64_t
61
+ ca_round_uint64 (uint64_t ax, long k, int *overflow)
62
+ {
63
+ uint64_t y = 1, q, rem, r;
64
+ long i;
65
+
66
+ *overflow = 0;
67
+ if ( k > 19 ) { /* 10**20 / 2 exceeds every 64-bit value */
68
+ return 0;
69
+ }
70
+ for (i = 0; i < k; i++) {
71
+ y *= 10;
72
+ }
73
+ q = ax / y;
74
+ rem = ax % y;
75
+ r = q * y;
76
+ if ( rem >= y - y / 2 ) { /* rem * 2 >= y, without overflow */
77
+ if ( r > UINT64_MAX - y ) {
78
+ *overflow = 1;
79
+ return 0;
80
+ }
81
+ r += y;
82
+ }
83
+ return r;
84
+ }
85
+
86
+ /* x rounded as Float#round(ndigits) rounds it, for ndigits != 0. NaN and
87
+ the infinities are their own answer (Float#round raises for them when
88
+ ndigits <= 0; an array of floats keeps them as values). */
89
+ static double
90
+ ca_round_double (double x, long ndigits)
91
+ {
92
+ int binexp;
93
+
94
+ if ( x == 0.0 || ! isfinite(x) ) {
95
+ return x;
96
+ }
97
+ if ( ndigits > 0 ) {
98
+ frexp(x, &binexp);
99
+ if ( ca_round_overflow(ndigits, binexp) ) {
100
+ return x;
101
+ }
102
+ if ( ca_round_underflow(ndigits, binexp) ) {
103
+ return 0.0;
104
+ }
105
+ if ( ndigits > 14 ) {
106
+ /* pow(10, ndigits) may not be exact; Ruby rounds through a Rational. */
107
+ return NUM2DBL(rb_funcall(DBL2NUM(x), id_round, 1, LONG2NUM(ndigits)));
108
+ }
109
+ {
110
+ double f = pow(10, (double) ndigits);
111
+ return ca_round_half_up(x, f) / f;
112
+ }
113
+ }
114
+ else {
115
+ /* Ruby truncates to an Integer, then rounds the Integer. */
116
+ double t = trunc(x);
117
+ if ( fabs(t) < 18446744073709551616.0 ) { /* 2**64 */
118
+ int overflow;
119
+ uint64_t r = ca_round_uint64((uint64_t) fabs(t), -ndigits, &overflow);
120
+ if ( ! overflow ) {
121
+ return ( t < 0 ) ? -(double) r : (double) r;
122
+ }
123
+ }
124
+ return NUM2DBL(rb_funcall(DBL2NUM(x), id_round, 1, LONG2NUM(ndigits)));
125
+ }
126
+ }
127
+
128
+ #define ROUND_INT_LOOP(type, lo, hi, is_signed) \
129
+ { \
130
+ type *p = (type *) ca->ptr; \
131
+ for (i = 0; i < ca->elements; i++) { \
132
+ int neg, overflow; \
133
+ uint64_t ax, r; \
134
+ if ( m && m[i] ) continue; \
135
+ neg = ( is_signed ) && ( (int64_t) p[i] < 0 ); \
136
+ ax = neg ? (uint64_t) 0 - (uint64_t)(int64_t) p[i] : (uint64_t) p[i]; \
137
+ r = ca_round_uint64(ax, -ndigits, &overflow); \
138
+ if ( overflow || ( neg ? r > (uint64_t) 0 - (uint64_t)(int64_t)(lo) \
139
+ : r > (uint64_t)(hi) ) ) { \
140
+ rb_raise(rb_eRangeError, \
141
+ "round: a value rounded to %ld digits does not fit " \
142
+ "data_type %s", ndigits, ca_type_name[ca->data_type]); \
143
+ } \
144
+ p[i] = neg ? (type)((uint64_t) 0 - r) : (type) r; \
145
+ } \
146
+ }
147
+
148
+ /* Rounds the cells of the entity `ca` in place; masked cells are left. */
149
+ static void
150
+ ca_round_entity (CArray *ca, long ndigits)
151
+ {
152
+ boolean8_t *m = NULL;
153
+ ca_size_t i;
154
+
155
+ if ( ca->mask ) {
156
+ m = (boolean8_t *) ca->mask->ptr;
157
+ }
158
+
159
+ switch ( ca->data_type ) {
160
+ case CA_INT8: ROUND_INT_LOOP(int8_t, INT8_MIN, INT8_MAX, 1); break;
161
+ case CA_UINT8: ROUND_INT_LOOP(uint8_t, 0, UINT8_MAX, 0); break;
162
+ case CA_INT16: ROUND_INT_LOOP(int16_t, INT16_MIN, INT16_MAX, 1); break;
163
+ case CA_UINT16: ROUND_INT_LOOP(uint16_t, 0, UINT16_MAX, 0); break;
164
+ case CA_INT32: ROUND_INT_LOOP(int32_t, INT32_MIN, INT32_MAX, 1); break;
165
+ case CA_UINT32: ROUND_INT_LOOP(uint32_t, 0, UINT32_MAX, 0); break;
166
+ case CA_INT64: ROUND_INT_LOOP(int64_t, INT64_MIN, INT64_MAX, 1); break;
167
+ case CA_UINT64: ROUND_INT_LOOP(uint64_t, 0, UINT64_MAX, 0); break;
168
+ case CA_FLOAT32: {
169
+ float32_t *p = (float32_t *) ca->ptr;
170
+ for (i = 0; i < ca->elements; i++) {
171
+ if ( m && m[i] ) continue;
172
+ p[i] = (float32_t) ca_round_double((double) p[i], ndigits);
173
+ }
174
+ break;
175
+ }
176
+ case CA_FLOAT64: {
177
+ float64_t *p = (float64_t *) ca->ptr;
178
+ for (i = 0; i < ca->elements; i++) {
179
+ if ( m && m[i] ) continue;
180
+ p[i] = ca_round_double(p[i], ndigits);
181
+ }
182
+ break;
183
+ }
184
+ case CA_OBJECT: {
185
+ VALUE *p = (VALUE *) ca->ptr;
186
+ volatile VALUE nd = LONG2NUM(ndigits);
187
+ for (i = 0; i < ca->elements; i++) {
188
+ if ( m && m[i] ) continue;
189
+ p[i] = rb_funcall(p[i], id_round, 1, nd);
190
+ }
191
+ break;
192
+ }
193
+ default:
194
+ rb_raise(rb_eCADataTypeError, "round: not defined for data_type %s",
195
+ ca_type_name[ca->data_type]);
196
+ }
197
+ }
198
+
199
+ /* The array to round: a boolean is rounded as its 0/1 int64 values, as
200
+ round without digits does. */
201
+ static VALUE
202
+ ca_round_source (VALUE self, VALUE vdigits, long *ndigits)
203
+ {
204
+ CArray *ca;
205
+ *ndigits = ca_integer_arg(vdigits, "ndigits", "round");
206
+ ca_face_refuse_numeric(self, "round", rb_eCADataTypeError);
207
+ GetCArray(self, ca);
208
+ if ( ca->data_type == CA_BOOLEAN ) {
209
+ self = rb_ca_wrap_readonly(self, INT2NUM(CA_INT64));
210
+ }
211
+ return self;
212
+ }
213
+
214
+ /* A copy of `src` rounded to `ndigits`. Rounding to 0 digits is what round
215
+ without digits does (except for objects, which are asked with the digits);
216
+ an integer has no digits below 10**0 to round. */
217
+ static VALUE
218
+ ca_round_copy (VALUE src, long ndigits)
219
+ {
220
+ volatile VALUE out;
221
+ CArray *ca, *co;
222
+ GetCArray(src, ca);
223
+ if ( ndigits == 0 && ca->data_type != CA_OBJECT ) {
224
+ return rb_ca_round(src);
225
+ }
226
+ out = rb_ca_copy(src);
227
+ GetCArray(out, co);
228
+ if ( ndigits > 0 && ca_is_integer_type(co) ) {
229
+ return out;
230
+ }
231
+ ca_round_entity(co, ndigits);
232
+ return out;
233
+ }
234
+
235
+ static VALUE
236
+ rb_ca_round_digits (int argc, VALUE *argv, VALUE self)
237
+ {
238
+ long ndigits;
239
+ rb_check_arity(argc, 0, 1);
240
+ if ( argc == 0 ) {
241
+ return rb_ca_round(self);
242
+ }
243
+ self = ca_round_source(self, argv[0], &ndigits);
244
+ return ca_round_copy(self, ndigits);
245
+ }
246
+
247
+ static VALUE
248
+ rb_ca_round_digits_bang (int argc, VALUE *argv, VALUE self)
249
+ {
250
+ long ndigits;
251
+ volatile VALUE src, out;
252
+ rb_check_arity(argc, 0, 1);
253
+ if ( argc == 0 ) {
254
+ return rb_ca_round_bang(self);
255
+ }
256
+ rb_ca_modify(self);
257
+ src = ca_round_source(self, argv[0], &ndigits);
258
+ if ( src != self ) {
259
+ rb_raise(rb_eCADataTypeError,
260
+ "round!: a boolean array can not hold the rounded int64 values");
261
+ }
262
+ out = ca_round_copy(self, ndigits);
263
+ rb_ca_store_all(self, out);
264
+ return self;
265
+ }
266
+
267
+ void
268
+ Init_carray_round (void)
269
+ {
270
+ id_round = rb_intern("round");
271
+ rb_define_method(rb_cCArray, "round", rb_ca_round_digits, -1);
272
+ rb_define_method(rb_cCArray, "round!", rb_ca_round_digits_bang, -1);
273
+ }
data/ext/carray_scatter.c CHANGED
@@ -13,8 +13,11 @@
13
13
  min / max: real numeric only (complex has no order)
14
14
  (boolean / object / fixlen → CADataTypeError; the bang
15
15
  cannot widen self, same rationale as fma! / fms!)
16
- replace: numeric or boolean (assignment, no widening)
17
- scalar Integer / Float, and Complex when self is complex
16
+ replace: any type (assignment, no widening); an object or
17
+ fixlen array is written through the indexer
18
+ scalar any Numeric, true / false, or UNDEF; converted to self's
19
+ type as the indexer's store converts it (a value that does
20
+ not fit raises, as `self[i] = v` does)
18
21
 
19
22
  --------------------------------------------------------------------------- */
20
23
 
@@ -44,17 +47,24 @@
44
47
  #define OP_MIN_INT(qp, v) do { if ((v) < *(qp)) *(qp) = (v); } while (0)
45
48
  #define OP_MAX_INT(qp, v) do { if ((v) > *(qp)) *(qp) = (v); } while (0)
46
49
 
47
- /* The scalar operand as T. An Integer goes to T directly, not through
48
- double, so an int64 above 2**53 is exact. A complex self also takes a
49
- Ruby Complex scalar, whose parts sit in vd / vi; an Integer or Float
50
- scalar leaves vi at 0. */
51
- #define SCALAR_REAL(T) (v_is_float ? (T) vd : (T) vl)
52
- #define SCALAR_CMPLX(T) ((T) ((v_is_float ? (double)vd : (double)vl) + vi * I))
50
+ /* The scalar operand, already converted to self's type by rb_ca_obj2ptr
51
+ (the indexer's store conversion) and held as one cell in vcell. */
52
+ typedef union {
53
+ char bytes[16];
54
+ double d;
55
+ int64_t l;
56
+ #ifdef HAVE_COMPLEX_H
57
+ cmplx128_t z;
58
+ #endif
59
+ } ca_scatter_cell_t;
60
+
61
+ #define SCALAR_REAL(T) (*(const T *) vcell.bytes)
62
+ #define SCALAR_CMPLX(T) (*(const T *) vcell.bytes)
53
63
 
54
64
  #define LOOP_SCALAR(T, APPLY) LOOP_SCALAR_V(T, APPLY, SCALAR_REAL(T))
55
65
 
56
66
  #define LOOP_SCALAR_V(T, APPLY, VS) do { \
57
- T *q = (T *) qbase; \
67
+ CA_U(T) *q = (CA_U(T) *) qbase; \
58
68
  T vs = VS; \
59
69
  if ( mself ) { \
60
70
  for (i = 0; i < n; i++) { \
@@ -76,8 +86,8 @@
76
86
  } while (0)
77
87
 
78
88
  #define LOOP_VEC(T, APPLY) do { \
79
- T *q = (T *) qbase; \
80
- T *r = (T *) cv->ptr; \
89
+ CA_U(T) *q = (CA_U(T) *) qbase; \
90
+ CA_U(T) *r = (CA_U(T) *) cv->ptr; \
81
91
  if ( mself ) { \
82
92
  for (i = 0; i < n; i++) { \
83
93
  if ( maddrs && maddrs[i] ) continue; \
@@ -105,26 +115,30 @@
105
115
  both value and mask (indexer contract, `self[addrs] = vals`).
106
116
  - masked vals[i] flips target to masked (writes UNDEF); valid
107
117
  vals[i] writes value and clears the target's mask bit.
108
- Scalar vals is always valid (Fixnum / Float), so scalar path just
109
- writes and clears target mask. */
118
+ A scalar UNDEF masks every target (self's mask exists by then); any
119
+ other scalar writes and clears the target's mask. */
110
120
 
111
121
  #define LOOP_SCALAR_REPLACE(T) LOOP_SCALAR_REPLACE_V(T, SCALAR_REAL(T))
112
122
 
113
123
  #define LOOP_SCALAR_REPLACE_V(T, VS) do { \
114
- T *q = (T *) qbase; \
124
+ CA_U(T) *q = (CA_U(T) *) qbase; \
115
125
  T vs = VS; \
116
126
  for (i = 0; i < n; i++) { \
117
127
  if ( maddrs && maddrs[i] ) continue; \
118
128
  addr = p[i]; \
119
129
  CA_CHECK_INDEX(addr, elements); \
130
+ if ( vals_undef ) { \
131
+ mself[addr] = 1; \
132
+ continue; \
133
+ } \
120
134
  q[addr] = vs; \
121
135
  if ( mself ) mself[addr] = 0; \
122
136
  } \
123
137
  } while (0)
124
138
 
125
139
  #define LOOP_VEC_REPLACE(T) do { \
126
- T *q = (T *) qbase; \
127
- T *r = (T *) cv->ptr; \
140
+ CA_U(T) *q = (CA_U(T) *) qbase; \
141
+ CA_U(T) *r = (CA_U(T) *) cv->ptr; \
128
142
  for (i = 0; i < n; i++) { \
129
143
  if ( maddrs && maddrs[i] ) continue; \
130
144
  addr = p[i]; \
@@ -204,11 +218,21 @@
204
218
  } \
205
219
  } while (0)
206
220
 
221
+ /* A value that is one cell for every address: a Numeric, true / false,
222
+ or UNDEF. Anything else (a CArray, an Array, ...) is coerced to an
223
+ array of values. */
224
+ static int
225
+ ca_scatter_is_scalar (VALUE v)
226
+ {
227
+ return v == CA_UNDEF || v == Qtrue || v == Qfalse
228
+ || rb_obj_is_kind_of(v, rb_cNumeric);
229
+ }
230
+
207
231
  /* Setup boilerplate: parse args and wrap addrs/vals.
208
232
 
209
233
  Outputs into caller's locals:
210
234
  ca, ci, cv (CArray*), n (ca_size_t),
211
- vals_scalar (int), v_is_float (int), vd, vi (double), vl (long).
235
+ vals_scalar, vals_undef (int), vcell (the scalar as one cell).
212
236
 
213
237
  The kernel then runs through AT_RUN, and an address out of range
214
238
  raising part way still leaves the cells already written.
@@ -218,9 +242,12 @@
218
242
  */
219
243
  /* Body shared by arithmetic and replace setups. Caller precondition:
220
244
  the data_type gate has already run (arithmetic = numeric only, replace
221
- = numeric or boolean). For the replace variant, `true` / `false`
222
- scalars are accepted as vals (bridged as vl = 1 / 0). */
223
- #define AT_SETUP_BODY(name, allow_bool_scalar) \
245
+ = numeric or boolean). A scalar is converted the way `self[i] = v`
246
+ converts it, so true / false reach only a boolean self and a value that
247
+ does not fit raises. A scalar UNDEF is a masked value: the arithmetic
248
+ family skips every pair, replace masks every target. */
249
+ #define AT_SETUP_BODY(name) \
250
+ ca_check_index_array(raddrs); \
224
251
  raddrs = rb_ca_wrap_readonly(raddrs, INT2NUM(CA_SIZE)); \
225
252
  TypedData_Get_Struct(raddrs, CArray, &carray_data_type, ci); \
226
253
  if ( ca_shares_root(ci, ca) ) { \
@@ -229,20 +256,17 @@
229
256
  } \
230
257
  n = ci->elements; \
231
258
  if ( n == 0 ) return self; \
232
- vals_scalar = (RB_FLOAT_TYPE_P(rvals) || FIXNUM_P(rvals) \
233
- || ((allow_bool_scalar) && (rvals == Qtrue || rvals == Qfalse)) \
234
- || (ca_is_complex_type(ca) && RB_TYPE_P(rvals, T_COMPLEX))); \
259
+ vals_scalar = ca_scatter_is_scalar(rvals); \
235
260
  if ( vals_scalar ) { \
236
- if ( RB_TYPE_P(rvals, T_COMPLEX) ) { \
237
- vd = NUM2DBL(rb_complex_real(rvals)); \
238
- vi = NUM2DBL(rb_complex_imag(rvals)); \
239
- v_is_float = 1; \
261
+ if ( rvals == CA_UNDEF ) { \
262
+ vals_undef = 1; \
263
+ } \
264
+ else { \
265
+ rb_ca_obj2ptr(self, rvals, vcell.bytes); \
240
266
  } \
241
- else if ( RB_FLOAT_TYPE_P(rvals) ) { vd = RFLOAT_VALUE(rvals); v_is_float = 1; } \
242
- else if ( FIXNUM_P(rvals) ) { vl = FIX2LONG(rvals); v_is_float = 0; } \
243
- else { vl = (rvals == Qtrue) ? 1 : 0; v_is_float = 0; } \
244
267
  } \
245
268
  else { \
269
+ /* coerce: a store into the receiver */ \
246
270
  rvals = rb_ca_wrap_readonly(rvals, INT2NUM(ca->data_type)); \
247
271
  TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv); \
248
272
  if ( ca_shares_root(cv, ca) ) { \
@@ -259,8 +283,8 @@
259
283
  #define AT_SETUP_LOCALS \
260
284
  CArray *ca, *ci, *cv = NULL; \
261
285
  ca_size_t n; \
262
- int vals_scalar, v_is_float = 0; \
263
- double vd = 0.0, vi = 0.0; long vl = 0;
286
+ int vals_scalar, vals_undef = 0; \
287
+ ca_scatter_cell_t vcell = {{0}};
264
288
 
265
289
  #define AT_SETUP_OR_RETURN(name, ordered) \
266
290
  AT_SETUP_LOCALS \
@@ -273,7 +297,8 @@
273
297
  rb_raise(rb_eCADataTypeError, \
274
298
  name " requires a real array (complex values have no order)"); \
275
299
  } \
276
- AT_SETUP_BODY(name, 0)
300
+ AT_SETUP_BODY(name) \
301
+ if ( vals_undef ) return self;
277
302
 
278
303
  /* replace variant: accepts boolean self (assignment, no widening) and
279
304
  Ruby true / false as scalar vals. */
@@ -285,7 +310,8 @@
285
310
  rb_raise(rb_eCADataTypeError, \
286
311
  name " requires a numeric or boolean array"); \
287
312
  } \
288
- AT_SETUP_BODY(name, 1)
313
+ AT_SETUP_BODY(name) \
314
+ if ( vals_undef ) ca_create_mask(ca);
289
315
 
290
316
  /* The kernel works either on self's own memory or on a compact region:
291
317
  the distinct cells the addresses touch, read out of self and written
@@ -305,9 +331,8 @@ typedef struct {
305
331
  typedef struct {
306
332
  CArray *ca, *ci, *cv;
307
333
  ca_size_t n;
308
- int vals_scalar, v_is_float;
309
- double vd, vi;
310
- long vl;
334
+ int vals_scalar, vals_undef;
335
+ ca_scatter_cell_t vcell;
311
336
  ca_scatter_region_t *region;
312
337
  } ca_scatter_ctx_t;
313
338
 
@@ -330,10 +355,9 @@ fname (VALUE arg) \
330
355
  boolean8_t *mvals = (cv && cv->mask) ? (boolean8_t *) cv->mask->ptr : NULL; \
331
356
  boolean8_t *mself = rg_ ? rg_->mask \
332
357
  : (ca->mask ? (boolean8_t *) ca->mask->ptr : NULL); \
333
- int vals_scalar = c_->vals_scalar, v_is_float = c_->v_is_float; \
334
- double vd = c_->vd, vi = c_->vi; \
335
- long vl = c_->vl; \
336
- (void) cv; (void) mvals; (void) v_is_float; (void) vd; (void) vi; (void) vl; \
358
+ int vals_scalar = c_->vals_scalar, vals_undef = c_->vals_undef; \
359
+ ca_scatter_cell_t vcell = c_->vcell; \
360
+ (void) cv; (void) mvals; (void) vals_undef; (void) vcell; \
337
361
  DISPATCH; \
338
362
  return Qnil; \
339
363
  }
@@ -460,8 +484,8 @@ ca_scatter_region_body (VALUE varg)
460
484
  ca_scatter_ctx_t c_; \
461
485
  CArray *list_[3]; \
462
486
  c_.ca = ca; c_.ci = ci; c_.cv = cv; c_.n = n; \
463
- c_.vals_scalar = vals_scalar; c_.v_is_float = v_is_float; \
464
- c_.vd = vd; c_.vi = vi; c_.vl = vl; \
487
+ c_.vals_scalar = vals_scalar; c_.vals_undef = vals_undef; \
488
+ c_.vcell = vcell; \
465
489
  c_.region = NULL; \
466
490
  if ( ca_attach_is_alias(ca) ) { \
467
491
  list_[0] = ca; list_[1] = ci; list_[2] = cv; \
@@ -474,6 +498,9 @@ ca_scatter_region_body (VALUE varg)
474
498
  ca_attach_window(vals_scalar ? 1 : 2, list_, "rr", \
475
499
  ca_scatter_region_body, (VALUE) &ra_); \
476
500
  } \
501
+ /* the views AT_SETUP_BODY made are reached only through ci and cv */ \
502
+ RB_GC_GUARD(raddrs); \
503
+ RB_GC_GUARD(rvals); \
477
504
  } while (0)
478
505
 
479
506
  /* --------------------------------------------------------------- */
@@ -566,11 +593,26 @@ AT_BODY(ca_scatter_replace_body, DISPATCH_NUMERIC_REPLACE())
566
593
  static VALUE
567
594
  rb_ca_scatter_replace_bang (VALUE self, VALUE raddrs, VALUE rvals)
568
595
  {
596
+ /* An object or fixlen array takes the assignment through the indexer,
597
+ which reads and writes its cells by their own rules (a VALUE kept
598
+ visible to the GC, a fixlen value fitted to the cell); the kernel
599
+ below is for the numeric and boolean cells. */
600
+ {
601
+ CArray *cs;
602
+ TypedData_Get_Struct(self, CArray, &carray_data_type, cs);
603
+ if ( cs->data_type == CA_OBJECT || cs->data_type == CA_FIXLEN ) {
604
+ rb_ca_modify(self);
605
+ if ( RB_TYPE_P(raddrs, T_ARRAY) ) { /* a list of addresses */
606
+ raddrs = rb_ca_wrap_readonly(raddrs, INT2NUM(CA_SIZE));
607
+ }
608
+ rb_funcall(rb_ca_flatten(self), rb_intern("[]="), 2, raddrs, rvals);
609
+ return self;
610
+ }
611
+ }
569
612
  /* Pre-scan: if vals is a masked CArray and self isn't yet masked,
570
613
  promote self so the kernel can flip target cells to masked (indexer
571
614
  `self[addrs] = vals` establishes self.mask lazily the same way). */
572
- if ( ! (RB_FLOAT_TYPE_P(rvals) || FIXNUM_P(rvals))
573
- && rb_obj_is_carray(rvals) ) {
615
+ if ( rb_obj_is_carray(rvals) ) {
574
616
  CArray *cv_pre;
575
617
  TypedData_Get_Struct(rvals, CArray, &carray_data_type, cv_pre);
576
618
  if ( ca_has_mask(cv_pre) ) {
data/ext/carray_segment.c CHANGED
@@ -228,7 +228,7 @@ rb_ca_s_segment_index (int argc, VALUE *argv, VALUE klass)
228
228
  return rout;
229
229
  }
230
230
 
231
- /* CArray.__segment_bounds__(name, lengths: l | offsets: o) -> int64[k+1]
231
+ /* CArray.__segment_boundaries_from_lengths_or_offsets__(name, lengths: l | offsets: o) -> int64[k+1]
232
232
 
233
233
  Internal: the validated boundaries, for a Ruby caller that takes the same
234
234
  two keywords (CArray#segments). `name` heads the error messages. */
@@ -239,7 +239,7 @@ rb_ca_s_segment_bounds (int argc, VALUE *argv, VALUE klass)
239
239
  ca_size_t k;
240
240
  VALUE rname;
241
241
  if ( argc < 1 ) {
242
- rb_raise(rb_eArgError, "__segment_bounds__: the caller's name is required");
242
+ rb_raise(rb_eArgError, "__segment_boundaries_from_lengths_or_offsets__: the caller's name is required");
243
243
  }
244
244
  rname = argv[0];
245
245
  StringValue(rname);
@@ -253,5 +253,5 @@ Init_carray_segment (void)
253
253
  id_offsets = rb_intern("offsets");
254
254
  rb_define_singleton_method(rb_cCArray, "segment_offsets", rb_ca_s_segment_offsets, -1);
255
255
  rb_define_singleton_method(rb_cCArray, "segment_index", rb_ca_s_segment_index, -1);
256
- rb_define_singleton_method(rb_cCArray, "__segment_bounds__", rb_ca_s_segment_bounds, -1);
256
+ rb_define_singleton_method(rb_cCArray, "__segment_boundaries_from_lengths_or_offsets__", rb_ca_s_segment_bounds, -1);
257
257
  }