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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +469 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +14 -26
- data/ext/ca_axis_group.c +27 -27
- data/ext/ca_binop_dispatch.c +1 -29
- data/ext/ca_binop_dispatch.h +0 -1
- data/ext/ca_categorical_iterator.c +231 -153
- data/ext/ca_compare.c +9 -20
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1240 -2000
- data/ext/ca_kernel_iterator.h +502 -519
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +152 -45
- data/ext/ca_obj_bincmp.c +25 -21
- data/ext/ca_obj_binop.c +16 -26
- data/ext/ca_obj_bitarray.c +8 -3
- data/ext/ca_obj_bitfield.c +63 -49
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +7 -7
- data/ext/ca_obj_const_string.c +188 -22
- data/ext/ca_obj_face.c +280 -58
- data/ext/ca_obj_face.h +19 -0
- data/ext/ca_obj_fake.c +15 -29
- data/ext/ca_obj_farray.c +6 -3
- data/ext/ca_obj_field.c +30 -8
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +455 -134
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +113 -67
- data/ext/ca_obj_object.c +210 -52
- data/ext/ca_obj_record.c +15 -7
- data/ext/ca_obj_reduce.c +17 -8
- data/ext/ca_obj_refer.c +42 -35
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +31 -10
- data/ext/ca_obj_select.c +48 -14
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +41 -7
- data/ext/ca_obj_stack.c +180 -34
- data/ext/ca_obj_stride.c +190 -134
- data/ext/ca_obj_string.c +80 -4
- data/ext/ca_obj_tile.c +32 -11
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +13 -7
- data/ext/ca_obj_triop.c +26 -32
- data/ext/ca_obj_window.c +267 -74
- data/ext/ca_op_ipower.c +4 -4
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +214 -75
- data/ext/carray_access.c +200 -99
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +113 -6
- data/ext/carray_bincount.c +10 -8
- data/ext/carray_broadcast.c +13 -8
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +108 -0
- data/ext/carray_cast.c +375 -96
- data/ext/carray_cast_func.rb +90 -20
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +18 -9
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +150 -55
- data/ext/carray_count.c +56 -20
- data/ext/carray_element.c +81 -33
- data/ext/carray_factorize.c +138 -84
- data/ext/carray_generate.c +199 -52
- data/ext/carray_histogram.c +63 -18
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +348 -29
- data/ext/carray_kernels_bincmp.c +4453 -0
- data/ext/carray_kernels_binop.c +11368 -0
- data/ext/carray_kernels_init.c +1734 -0
- data/ext/carray_kernels_moncmp.c +2104 -0
- data/ext/carray_kernels_monop.c +18369 -0
- data/ext/carray_kernels_reduce_aggregate.c +23818 -0
- data/ext/carray_kernels_reduce_boolean.c +406 -0
- data/ext/carray_kernels_reduce_cumulative.c +10086 -0
- data/ext/carray_kernels_reduce_extreme.c +17634 -0
- data/ext/carray_kernels_reduce_variance.c +3849 -0
- data/ext/carray_kernels_scan.c +4302 -0
- data/ext/carray_kernels_search.c +33829 -0
- data/ext/carray_kernels_sort.c +10897 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +220 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +337 -94
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +129 -52
- data/ext/carray_order.c +604 -77
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +85 -31
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +87 -45
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +123 -37
- data/ext/carray_sort.c +259 -51
- data/ext/carray_sort_kernel.c +5 -7
- data/ext/carray_struct.c +54 -61
- data/ext/carray_test.c +26 -5
- data/ext/carray_time_text.c +4 -2
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +309 -66
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +403 -350
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +139 -22
- data/lib/carray/autoload_carray.rb +8 -31
- data/lib/carray/autoload_method_extension.rb +14 -5
- data/lib/carray/axis_group.rb +255 -106
- data/lib/carray/basics.rb +105 -17
- data/lib/carray/bincount_nd.rb +12 -2
- data/lib/carray/block_iterator.rb +126 -23
- data/lib/carray/boolean_reduce.rb +17 -17
- data/lib/carray/categorical.rb +195 -59
- data/lib/carray/categorical_iterator.rb +132 -29
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +24 -5
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +9 -1
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +48 -3
- data/lib/carray/frame/column_verbs.rb +71 -0
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/convert.rb +69 -0
- data/lib/carray/frame/csv_parser.rb +111 -17
- data/lib/carray/frame/describe.rb +3 -2
- data/lib/carray/frame/frame.rb +252 -28
- data/lib/carray/frame/group.rb +603 -101
- data/lib/carray/frame/io.rb +117 -28
- data/lib/carray/frame/join.rb +312 -51
- data/lib/carray/frame/records.rb +83 -7
- data/lib/carray/frame/reshape.rb +42 -35
- data/lib/carray/frame/sort.rb +7 -19
- data/lib/carray/frame/verbs.rb +188 -48
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +42 -6
- data/lib/carray/fusion.rb +40 -16
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +31 -8
- data/lib/carray/iterator.rb +85 -7
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +217 -183
- data/lib/carray/mask_gap_fill.rb +63 -57
- data/lib/carray/meld_reduce.rb +12 -14
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +16 -0
- data/lib/carray/methods/bit_string.rb +1 -1
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +3 -1
- data/lib/carray/methods/gather_nd.rb +14 -5
- data/lib/carray/methods/insert_block.rb +2 -2
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +61 -37
- data/lib/carray/methods/join.rb +1 -6
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +47 -51
- data/lib/carray/methods/mode.rb +1 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/resize.rb +3 -3
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +3 -3
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +53 -8
- data/lib/carray/segment_iterator.rb +323 -88
- data/lib/carray/serialize.rb +45 -14
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/stack.rb +15 -12
- data/lib/carray/string.rb +113 -5
- data/lib/carray/string_operation_extension.rb +21 -6
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +24 -11
- data/lib/carray/time.rb +819 -158
- data/lib/carray/window_iterator.rb +122 -16
- data/lib/carray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +4 -0
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +2 -1
- data/yard-stubs/ca_obj_roll.rb +2 -2
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +3 -6
- data/yard-stubs/carray_cast.rb +12 -0
- data/yard-stubs/carray_conversion.rb +7 -2
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +17 -10
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +32 -3
- data/yard-stubs/carray_math.rb +41 -5
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +129 -22
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +17 -10
- data/yard-stubs/carray_slab.rb +9 -2
- data/yard-stubs/carray_sort.rb +6 -5
- data/yard-stubs/carray_test.rb +5 -3
- metadata +25 -3
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_round.c
ADDED
|
@@ -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:
|
|
17
|
-
|
|
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
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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),
|
|
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).
|
|
222
|
-
|
|
223
|
-
|
|
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 = (
|
|
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 (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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,
|
|
263
|
-
|
|
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
|
|
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
|
|
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,
|
|
309
|
-
|
|
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,
|
|
334
|
-
|
|
335
|
-
|
|
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_.
|
|
464
|
-
c_.
|
|
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 (
|
|
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.
|
|
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, "
|
|
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, "
|
|
256
|
+
rb_define_singleton_method(rb_cCArray, "__segment_boundaries_from_lengths_or_offsets__", rb_ca_s_segment_bounds, -1);
|
|
257
257
|
}
|