carray 3.0.1 → 3.0.3
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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_math_kernel.h
CHANGED
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
|
|
42
42
|
#include "ruby.h"
|
|
43
43
|
#include "carray.h"
|
|
44
|
+
#include "carray_internal.h" /* ca_integer_arg, ca_calling_method_name */
|
|
45
|
+
#include "ca_obj_face.h" /* ca_face_refuse_numeric */
|
|
44
46
|
#include <math.h>
|
|
45
47
|
|
|
46
48
|
/* Externals (link-time; kept out of carray.h to keep the header lean). */
|
|
@@ -50,6 +52,7 @@ extern VALUE rb_ca_insert_axis (int argc, VALUE *argv, VALUE self); /* c
|
|
|
50
52
|
static ID id_axis, id_sort_copy, id_is_not_masked;
|
|
51
53
|
/* object lane (arbitrary Ruby objects -> arithmetic is irreducibly funcall) */
|
|
52
54
|
static ID id_plus, id_div, id_mul, id_min, id_max, id_sort, id_copy;
|
|
55
|
+
static ID id_rationalize;
|
|
53
56
|
static ID id_aref, id_aset;
|
|
54
57
|
static VALUE sym_linear, sym_lower, sym_higher, sym_nearest, sym_midpoint;
|
|
55
58
|
|
|
@@ -71,13 +74,14 @@ mp_is_numeric (int8_t dt)
|
|
|
71
74
|
_(CA_INT64, int64_t) _(CA_UINT64, uint64_t) \
|
|
72
75
|
_(CA_FLOAT32, float32_t) _(CA_FLOAT64, double)
|
|
73
76
|
|
|
74
|
-
/* [numeric]
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
fmin ignores NaN (fmin(x,NaN)==x), so a
|
|
78
|
-
NaN and stays branch-free
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
/* [numeric] sorted[k+1] of a fiber partitioned at k = the min over the
|
|
78
|
+
upper region [k+1, n-1]. NaN sorts after every number, so it is the
|
|
79
|
+
upper element only when the region holds nothing else. stride = element
|
|
80
|
+
stride along the reduce axis. fmin ignores NaN (fmin(x,NaN)==x), so a
|
|
81
|
+
+INFINITY seed skips NaN and the loop stays branch-free and vectorised.
|
|
82
|
+
A result of +INFINITY is either a +INFINITY in the region or a region of
|
|
83
|
+
NaN only; the rescan that tells them apart runs only in that case. An
|
|
84
|
+
empty region (k == n-1) answers the kth value. */
|
|
81
85
|
#define MP_GEN_MINUP(CT, T) \
|
|
82
86
|
static double \
|
|
83
87
|
mp_minup_##T (const T *b, ca_size_t f0, long k, long n, long stride) { \
|
|
@@ -86,8 +90,11 @@ mp_is_numeric (int8_t dt)
|
|
|
86
90
|
double v = (double) b[f0 + (ca_size_t)(ai * stride)]; \
|
|
87
91
|
hi = fmin(hi, v); \
|
|
88
92
|
} \
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
if ( hi != (double) INFINITY ) return hi; \
|
|
94
|
+
if ( k + 1 >= n ) return (double) b[f0 + (ca_size_t)(k * stride)]; \
|
|
95
|
+
for ( long ai = k + 1; ai < n; ai++ ) \
|
|
96
|
+
if ( (double) b[f0 + (ca_size_t)(ai * stride)] == hi ) return hi; \
|
|
97
|
+
return (double) NAN; \
|
|
91
98
|
}
|
|
92
99
|
MP_TYPES(MP_GEN_MINUP)
|
|
93
100
|
|
|
@@ -137,7 +144,12 @@ static VALUE
|
|
|
137
144
|
mp_axis_all_masked (VALUE self, long axis, int keep_axis)
|
|
138
145
|
{
|
|
139
146
|
int8_t ax = (int8_t) axis;
|
|
140
|
-
|
|
147
|
+
CArray *ca;
|
|
148
|
+
GetCArray(self, ca);
|
|
149
|
+
VALUE out = rb_ca_new_reduced(self, &ax, 1,
|
|
150
|
+
(ca->data_type == CA_OBJECT) ? CA_OBJECT
|
|
151
|
+
: CA_FLOAT64,
|
|
152
|
+
keep_axis);
|
|
141
153
|
CArray *co;
|
|
142
154
|
GetCArray(out, co);
|
|
143
155
|
ca_create_mask(co);
|
|
@@ -240,7 +252,7 @@ median_fill (double *op, int8_t dt, const char *base,
|
|
|
240
252
|
MP_TYPES(MP_CASE)
|
|
241
253
|
#undef MP_CASE
|
|
242
254
|
default:
|
|
243
|
-
rb_raise(rb_eCADataTypeError, "median:
|
|
255
|
+
rb_raise(rb_eCADataTypeError, "median: source data_type :%s not supported", ca_type_name[dt]);
|
|
244
256
|
}
|
|
245
257
|
}
|
|
246
258
|
|
|
@@ -298,13 +310,13 @@ median_flat (VALUE self, long min_count, VALUE fill_value, int keep_axis)
|
|
|
298
310
|
if ( RTEST(rb_ca_has_mask(self)) ) {
|
|
299
311
|
CArray *mc; GetCArray(self, mc);
|
|
300
312
|
long cnt = (long) ca_count_not_masked(mc); /* = elements - count_masked */
|
|
301
|
-
if ( cnt
|
|
313
|
+
if ( ca_too_few_present(cnt, min_count, 1) ) filled = 1;
|
|
302
314
|
else src = rb_ca_fetch(self, ID2SYM(id_is_not_masked));
|
|
303
315
|
}
|
|
304
316
|
if ( !filled ) {
|
|
305
317
|
CArray *sc;
|
|
306
318
|
GetCArray(src, sc);
|
|
307
|
-
if ( sc->elements
|
|
319
|
+
if ( ca_too_few_present(sc->elements, min_count, 1) ) filled = 1;
|
|
308
320
|
}
|
|
309
321
|
|
|
310
322
|
if ( filled ) {
|
|
@@ -336,6 +348,91 @@ median_flat (VALUE self, long min_count, VALUE fill_value, int keep_axis)
|
|
|
336
348
|
Every function in this block (down to the median entry) is [object].
|
|
337
349
|
===================================================================== */
|
|
338
350
|
|
|
351
|
+
/* [object] Is this operand's arithmetic the arithmetic interpolation means?
|
|
352
|
+
`lo` / `hi` are a stored object on the flat path and an object CArray of
|
|
353
|
+
them on the per-axis one, so look through a CArray to an element. An
|
|
354
|
+
empty one has nothing to interpolate and passes. */
|
|
355
|
+
static int
|
|
356
|
+
mp_object_interpolates (VALUE v)
|
|
357
|
+
{
|
|
358
|
+
if ( rb_obj_is_kind_of(v, rb_cNumeric) ) {
|
|
359
|
+
return 1;
|
|
360
|
+
}
|
|
361
|
+
if ( rb_obj_is_kind_of(v, rb_cCArray) ) {
|
|
362
|
+
CArray *ca;
|
|
363
|
+
ca_size_t i;
|
|
364
|
+
GetCArray(v, ca);
|
|
365
|
+
for ( i = 0; i < ca->elements; i++ ) {
|
|
366
|
+
VALUE e = rb_ca_fetch_addr(v, i);
|
|
367
|
+
if ( e != CA_UNDEF && ! rb_obj_is_kind_of(e, rb_cNumeric) ) {
|
|
368
|
+
return 0;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return 1;
|
|
372
|
+
}
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* [object] The element an interpolation refusal names: lo itself, or the
|
|
377
|
+
first element of a CArray of them that has no arithmetic. */
|
|
378
|
+
static VALUE
|
|
379
|
+
mp_first_non_numeric (VALUE v)
|
|
380
|
+
{
|
|
381
|
+
if ( rb_obj_is_kind_of(v, rb_cCArray) ) {
|
|
382
|
+
CArray *ca;
|
|
383
|
+
ca_size_t i;
|
|
384
|
+
GetCArray(v, ca);
|
|
385
|
+
for ( i = 0; i < ca->elements; i++ ) {
|
|
386
|
+
VALUE e = rb_ca_fetch_addr(v, i);
|
|
387
|
+
if ( e != CA_UNDEF && ! rb_obj_is_kind_of(e, rb_cNumeric) ) {
|
|
388
|
+
return e;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return v;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* [object] An order statistic answers in the elements' own terms: a pick
|
|
396
|
+
is the element itself, and an average or an interpolation is done with
|
|
397
|
+
the elements' own arithmetic and an exact weight, so a Rational or a
|
|
398
|
+
BigDecimal stays exact and a Float stays a Float. */
|
|
399
|
+
|
|
400
|
+
/* The interpolation weight r (0 <= r < 1) as a Rational. */
|
|
401
|
+
static VALUE
|
|
402
|
+
obj_weight (double r)
|
|
403
|
+
{
|
|
404
|
+
return rb_funcall(DBL2NUM(r), id_rationalize, 0);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/* The midpoint of lo and hi, (lo + hi) * (1/2): exact for an Integer or a
|
|
408
|
+
Rational, and the same for a cell (the flat path) and for a CArray of
|
|
409
|
+
them (the per-axis path). */
|
|
410
|
+
static VALUE
|
|
411
|
+
obj_midpoint (VALUE lo, VALUE hi)
|
|
412
|
+
{
|
|
413
|
+
return rb_funcall(rb_funcall(lo, id_plus, 1, hi), id_mul, 1,
|
|
414
|
+
rb_rational_new(INT2FIX(1), INT2FIX(2)));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* [object] Refuse to interpolate between two elements that have no
|
|
418
|
+
arithmetic meaning it. A String has both a `*` and a `+`, and
|
|
419
|
+
String#* truncates the Float weight to zero -- so :linear quietly
|
|
420
|
+
returned "" instead of failing, which is the reason this guard is
|
|
421
|
+
here rather than a rescue. The three picking methods need no
|
|
422
|
+
arithmetic and are the way through. */
|
|
423
|
+
static void
|
|
424
|
+
mp_require_interpolable (const char *who, VALUE method, VALUE lo)
|
|
425
|
+
{
|
|
426
|
+
if ( mp_object_interpolates(lo) ) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
rb_raise(rb_eCADataTypeError,
|
|
430
|
+
"%s: method: :%"PRIsVALUE" interpolates between two elements, "
|
|
431
|
+
"which %"PRIsVALUE" does not support; use method: :lower, :higher "
|
|
432
|
+
"or :nearest to pick an element instead",
|
|
433
|
+
who, rb_sym2str(method), rb_obj_class(mp_first_non_numeric(lo)));
|
|
434
|
+
}
|
|
435
|
+
|
|
339
436
|
/* [object] recv.mid(axis: raxis) -- e.g. min/max/sort along an axis. */
|
|
340
437
|
static VALUE
|
|
341
438
|
obj_call_axis (VALUE recv, ID mid, VALUE raxis)
|
|
@@ -419,10 +516,20 @@ median_object_axis (VALUE self, long axis, long n, int keep_axis)
|
|
|
419
516
|
long k = n / 2 - 1;
|
|
420
517
|
VALUE lo, hi;
|
|
421
518
|
obj_kth_pair(self, axis, k, n, &lo, &hi);
|
|
422
|
-
|
|
519
|
+
/* An even count has no middle element, only the average of two -- so
|
|
520
|
+
a column whose objects have no arithmetic has a median only at odd
|
|
521
|
+
length. percentile(50, method: :lower) names one either way. */
|
|
522
|
+
if ( ! mp_object_interpolates(lo) ) {
|
|
523
|
+
rb_raise(rb_eCADataTypeError,
|
|
524
|
+
"median: an even number of elements has no middle one, and "
|
|
525
|
+
"%"PRIsVALUE" cannot be averaged; use percentile(50, method: "
|
|
526
|
+
":lower) (or :higher / :nearest) to pick an element instead",
|
|
527
|
+
rb_obj_class(mp_first_non_numeric(lo)));
|
|
528
|
+
}
|
|
529
|
+
result = obj_midpoint(lo, hi);
|
|
423
530
|
} else {
|
|
424
531
|
VALUE kv = obj_kth_one(self, axis, (n - 1) / 2);
|
|
425
|
-
result =
|
|
532
|
+
result = kv;
|
|
426
533
|
}
|
|
427
534
|
if ( keep_axis ) {
|
|
428
535
|
VALUE ia[1] = { LONG2NUM(axis) };
|
|
@@ -440,13 +547,13 @@ median_object_flat (VALUE self, long min_count, VALUE fill_value, int keep_axis)
|
|
|
440
547
|
if ( RTEST(rb_ca_has_mask(self)) ) {
|
|
441
548
|
CArray *mc; GetCArray(self, mc);
|
|
442
549
|
long cnt = (long) ca_count_not_masked(mc); /* = elements - count_masked */
|
|
443
|
-
if ( cnt
|
|
550
|
+
if ( ca_too_few_present(cnt, min_count, 1) ) filled = 1;
|
|
444
551
|
else src = rb_ca_fetch(self, ID2SYM(id_is_not_masked));
|
|
445
552
|
}
|
|
446
553
|
if ( !filled ) {
|
|
447
554
|
CArray *sc;
|
|
448
555
|
GetCArray(src, sc);
|
|
449
|
-
if ( sc->elements
|
|
556
|
+
if ( ca_too_few_present(sc->elements, min_count, 1) ) filled = 1;
|
|
450
557
|
}
|
|
451
558
|
if ( filled ) {
|
|
452
559
|
result = NIL_P(fill_value) ? CA_UNDEF : fill_value;
|
|
@@ -464,29 +571,28 @@ median_object_flat (VALUE self, long min_count, VALUE fill_value, int keep_axis)
|
|
|
464
571
|
pre-fetched). Reached ONLY by CA_OBJECT percentile/quantile -- never
|
|
465
572
|
by numeric (that path uses pct_compute) and never by median.
|
|
466
573
|
The :linear / :midpoint interpolation funcalls are irreducible for
|
|
467
|
-
arbitrary objects; the
|
|
468
|
-
match the numeric "always Float" output contract. */
|
|
574
|
+
arbitrary objects; the pick methods return the element itself. */
|
|
469
575
|
static VALUE
|
|
470
576
|
pct_compute_object (VALUE method, long k, double r, long n, VALUE lo, VALUE hi)
|
|
471
577
|
{
|
|
472
|
-
if ( method == sym_lower ) return
|
|
473
|
-
if ( method == sym_higher )
|
|
474
|
-
VALUE v = (r == 0.0) ? lo : hi;
|
|
475
|
-
return rb_funcall(v, id_mul, 1, DBL2NUM(1.0));
|
|
476
|
-
}
|
|
578
|
+
if ( method == sym_lower ) return lo;
|
|
579
|
+
if ( method == sym_higher ) return (r == 0.0) ? lo : hi;
|
|
477
580
|
if ( method == sym_nearest ) {
|
|
478
581
|
int use_k = (r < 0.5) || (r == 0.5 && (k % 2 == 0));
|
|
479
|
-
return
|
|
582
|
+
return use_k ? lo : hi;
|
|
480
583
|
}
|
|
481
584
|
if ( method == sym_linear ) {
|
|
482
|
-
if ( r == 0.0 || k + 1 >= n ) return
|
|
483
|
-
|
|
484
|
-
VALUE
|
|
585
|
+
if ( r == 0.0 || k + 1 >= n ) return lo;
|
|
586
|
+
mp_require_interpolable("percentile", method, lo);
|
|
587
|
+
VALUE w = obj_weight(r);
|
|
588
|
+
VALUE a = rb_funcall(lo, id_mul, 1, rb_funcall(INT2FIX(1), rb_intern("-"), 1, w));
|
|
589
|
+
VALUE b = rb_funcall(hi, id_mul, 1, w);
|
|
485
590
|
return rb_funcall(a, id_plus, 1, b);
|
|
486
591
|
}
|
|
487
592
|
if ( method == sym_midpoint ) {
|
|
488
|
-
if ( k + 1 >= n ) return
|
|
489
|
-
|
|
593
|
+
if ( k + 1 >= n ) return lo;
|
|
594
|
+
mp_require_interpolable("percentile", method, lo);
|
|
595
|
+
return obj_midpoint(lo, hi);
|
|
490
596
|
}
|
|
491
597
|
rb_raise(rb_eArgError, "percentile: invalid method (BUG)");
|
|
492
598
|
}
|
|
@@ -495,11 +601,8 @@ pct_compute_object (VALUE method, long k, double r, long n, VALUE lo, VALUE hi)
|
|
|
495
601
|
static VALUE
|
|
496
602
|
pct_object_one_partition (VALUE self, long axis, long n, double p, VALUE method)
|
|
497
603
|
{
|
|
498
|
-
if ( p == 100.0 )
|
|
499
|
-
return rb_funcall(obj_call_axis(self, id_max, LONG2NUM(axis)),
|
|
500
|
-
id_mul, 1, DBL2NUM(1.0));
|
|
501
604
|
if ( n == 1 )
|
|
502
|
-
return
|
|
605
|
+
return obj_slice(self, axis, 0);
|
|
503
606
|
double f = (n - 1) * p / 100.0;
|
|
504
607
|
long k = (long) floor(f);
|
|
505
608
|
double r = f - k;
|
|
@@ -515,9 +618,9 @@ static VALUE
|
|
|
515
618
|
pct_object_one_sorted (VALUE sorted, long axis, long n, double p, VALUE method)
|
|
516
619
|
{
|
|
517
620
|
if ( p == 100.0 )
|
|
518
|
-
return
|
|
621
|
+
return obj_slice(sorted, axis, n - 1);
|
|
519
622
|
if ( n == 1 )
|
|
520
|
-
return
|
|
623
|
+
return obj_slice(sorted, axis, 0);
|
|
521
624
|
double f = (n - 1) * p / 100.0;
|
|
522
625
|
long k = (long) floor(f);
|
|
523
626
|
double r = f - k;
|
|
@@ -597,7 +700,7 @@ pct_object_axis_masked_one (VALUE self, VALUE sorted, long axis, double p,
|
|
|
597
700
|
for ( long j = 0; j < M; j++ )
|
|
598
701
|
if ( !sm[f0 + (ca_size_t)(j * INNER)] ) np++;
|
|
599
702
|
}
|
|
600
|
-
if ( np
|
|
703
|
+
if ( ca_too_few_present(np, min_count, 1) ) {
|
|
601
704
|
if ( is_undef ) {
|
|
602
705
|
if ( !co->mask ) ca_create_mask(co);
|
|
603
706
|
((boolean8_t *) co->mask->ptr)[oc] = 1;
|
|
@@ -683,13 +786,13 @@ percentile_object_flat (VALUE self, VALUE pers, long min_count, VALUE fill_value
|
|
|
683
786
|
if ( RTEST(rb_ca_has_mask(self)) ) {
|
|
684
787
|
CArray *mc; GetCArray(self, mc);
|
|
685
788
|
long cnt = (long) ca_count_not_masked(mc); /* = elements - count_masked */
|
|
686
|
-
if ( cnt
|
|
789
|
+
if ( ca_too_few_present(cnt, min_count, 1) ) filled = 1;
|
|
687
790
|
else src = rb_ca_fetch(self, ID2SYM(id_is_not_masked));
|
|
688
791
|
}
|
|
689
792
|
if ( !filled ) {
|
|
690
793
|
CArray *sc;
|
|
691
794
|
GetCArray(src, sc);
|
|
692
|
-
if ( sc->elements
|
|
795
|
+
if ( ca_too_few_present(sc->elements, min_count, 1) ) filled = 1;
|
|
693
796
|
}
|
|
694
797
|
if ( filled ) {
|
|
695
798
|
VALUE fill = NIL_P(fill_value) ? CA_UNDEF : fill_value;
|
|
@@ -710,7 +813,7 @@ static VALUE median_axis_masked (VALUE self, long axis, long min_count,
|
|
|
710
813
|
/* [entry] median(axis:, min_count:, fill_value:, keep_axis:). Dispatches
|
|
711
814
|
fixlen -> reject, object -> object lane, numeric -> numeric lane. */
|
|
712
815
|
static VALUE
|
|
713
|
-
|
|
816
|
+
rb_ca_median_m_body (int argc, VALUE *argv, VALUE self)
|
|
714
817
|
{
|
|
715
818
|
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
716
819
|
VALUE raxis = Qnil, rmin_count = INT2FIX(0), fill_value = Qnil, rkeep = Qfalse;
|
|
@@ -721,6 +824,15 @@ rb_ca_median_m (int argc, VALUE *argv, VALUE self)
|
|
|
721
824
|
|
|
722
825
|
CArray *ca;
|
|
723
826
|
GetCArray(self, ca);
|
|
827
|
+
/* A lazy expression is computed whole here, so a registered evaluator
|
|
828
|
+
may compute it instead. */
|
|
829
|
+
{
|
|
830
|
+
volatile VALUE evaluated = ca_lazy_evaluated(self);
|
|
831
|
+
if ( ! NIL_P(evaluated) ) {
|
|
832
|
+
self = evaluated;
|
|
833
|
+
GetCArray(self, ca);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
724
836
|
/* Boolean rides the f64 lane: 0/1 -> 0.0/1.0, so median interpolates and
|
|
725
837
|
returns a float (a 2-element median averages to 0.5), matching how the
|
|
726
838
|
numeric lane treats integer input. */
|
|
@@ -729,17 +841,25 @@ rb_ca_median_m (int argc, VALUE *argv, VALUE self)
|
|
|
729
841
|
GetCArray(self, ca);
|
|
730
842
|
}
|
|
731
843
|
int8_t dt = ca->data_type;
|
|
732
|
-
if ( ca_is_fixlen_type(ca) )
|
|
844
|
+
if ( ca_is_fixlen_type(ca) ) {
|
|
845
|
+
ca_face_refuse_numeric(self, "median", rb_eCADataTypeError);
|
|
733
846
|
rb_raise(rb_eCADataTypeError,
|
|
734
847
|
"median: not defined for fixlen (no numeric midpoint); "
|
|
735
848
|
"use a numeric or object array");
|
|
849
|
+
}
|
|
736
850
|
int is_obj = (dt == CA_OBJECT);
|
|
737
851
|
if ( !is_obj && !mp_is_numeric(dt) )
|
|
738
|
-
rb_raise(rb_eCADataTypeError, "median:
|
|
852
|
+
rb_raise(rb_eCADataTypeError, "median: source data_type :%s not supported", ca_type_name[dt]);
|
|
739
853
|
|
|
740
|
-
long min_count =
|
|
741
|
-
|
|
742
|
-
|
|
854
|
+
long min_count = ca_min_count_arg(rmin_count, NULL);
|
|
855
|
+
/* fill_value: UNDEF leaves the result undefined; any other fill is what
|
|
856
|
+
a store into the float64 result would make of it. */
|
|
857
|
+
if ( fill_value == CA_UNDEF ) {
|
|
858
|
+
fill_value = Qnil;
|
|
859
|
+
}
|
|
860
|
+
else if ( ! NIL_P(fill_value) && ! is_obj ) {
|
|
861
|
+
fill_value = ca_fill_as(fill_value, CA_FLOAT64);
|
|
862
|
+
}
|
|
743
863
|
int keep_axis = RTEST(rkeep);
|
|
744
864
|
|
|
745
865
|
if ( !NIL_P(raxis) ) {
|
|
@@ -803,7 +923,7 @@ pct_fill (double *op, int8_t dt, const char *base, int from_sorted,
|
|
|
803
923
|
MP_TYPES(MP_CASE)
|
|
804
924
|
#undef MP_CASE
|
|
805
925
|
default:
|
|
806
|
-
rb_raise(rb_eCADataTypeError, "percentile:
|
|
926
|
+
rb_raise(rb_eCADataTypeError, "percentile: source data_type :%s not supported", ca_type_name[dt]);
|
|
807
927
|
}
|
|
808
928
|
}
|
|
809
929
|
|
|
@@ -831,7 +951,7 @@ pct_fill (double *op, int8_t dt, const char *base, int from_sorted,
|
|
|
831
951
|
for ( long j = 0; j < M; j++ ) \
|
|
832
952
|
if ( !sm[f0 + (ca_size_t)(j * INNER)] ) np++; \
|
|
833
953
|
} \
|
|
834
|
-
if ( np
|
|
954
|
+
if ( ca_too_few_present(np, min_count, 1) ) { \
|
|
835
955
|
if ( is_undef ) { \
|
|
836
956
|
if ( !co->mask ) ca_create_mask(co); \
|
|
837
957
|
((boolean8_t *) co->mask->ptr)[oc] = 1; \
|
|
@@ -872,7 +992,7 @@ pct_fill_masked (CArray *co, int8_t dt, const char *base, const boolean8_t *sm,
|
|
|
872
992
|
MP_TYPES(MP_CASE)
|
|
873
993
|
#undef MP_CASE
|
|
874
994
|
default:
|
|
875
|
-
rb_raise(rb_eCADataTypeError, "percentile:
|
|
995
|
+
rb_raise(rb_eCADataTypeError, "percentile: source data_type :%s not supported", ca_type_name[dt]);
|
|
876
996
|
}
|
|
877
997
|
}
|
|
878
998
|
|
|
@@ -1061,7 +1181,7 @@ pct_flat (VALUE self, VALUE pers_ary, long min_count, VALUE fill_value,
|
|
|
1061
1181
|
if ( RTEST(rb_ca_has_mask(self)) ) {
|
|
1062
1182
|
CArray *mc; GetCArray(self, mc);
|
|
1063
1183
|
long cnt = (long) ca_count_not_masked(mc); /* = elements - count_masked */
|
|
1064
|
-
if ( cnt
|
|
1184
|
+
if ( ca_too_few_present(cnt, min_count, 1) ) {
|
|
1065
1185
|
masked_out = 1; is_undef = NIL_P(fill_value);
|
|
1066
1186
|
if ( !is_undef ) fillv = NUM2DBL(fill_value);
|
|
1067
1187
|
} else {
|
|
@@ -1071,7 +1191,7 @@ pct_flat (VALUE self, VALUE pers_ary, long min_count, VALUE fill_value,
|
|
|
1071
1191
|
if ( !masked_out ) {
|
|
1072
1192
|
CArray *sc;
|
|
1073
1193
|
GetCArray(src, sc);
|
|
1074
|
-
if ( sc->elements
|
|
1194
|
+
if ( ca_too_few_present(sc->elements, min_count, 1) ) {
|
|
1075
1195
|
masked_out = 1; is_undef = NIL_P(fill_value);
|
|
1076
1196
|
if ( !is_undef ) fillv = NUM2DBL(fill_value);
|
|
1077
1197
|
}
|
|
@@ -1119,7 +1239,10 @@ pct_flatten_validate_pers (VALUE pers)
|
|
|
1119
1239
|
rb_raise(rb_eArgError, "percentile: at least one p value required");
|
|
1120
1240
|
for ( long i = 0; i < len; i++ ) {
|
|
1121
1241
|
VALUE p = rb_ary_entry(pers, i);
|
|
1122
|
-
|
|
1242
|
+
/* Written as "inside", so that NaN -- which fails every comparison --
|
|
1243
|
+
is refused rather than let through. */
|
|
1244
|
+
if ( !rb_obj_is_kind_of(p, rb_cNumeric) ||
|
|
1245
|
+
!(NUM2DBL(p) >= 0.0 && NUM2DBL(p) <= 100.0) )
|
|
1123
1246
|
rb_raise(rb_eArgError,
|
|
1124
1247
|
"percentile: p must be Numeric in [0,100] (got %"PRIsVALUE")",
|
|
1125
1248
|
rb_inspect(p));
|
|
@@ -1131,9 +1254,8 @@ pct_flatten_validate_pers (VALUE pers)
|
|
|
1131
1254
|
keep_axis:). Dispatches fixlen -> reject, object -> object lane,
|
|
1132
1255
|
numeric -> numeric lane. */
|
|
1133
1256
|
static VALUE
|
|
1134
|
-
|
|
1257
|
+
rb_ca_percentile_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
|
|
1135
1258
|
{
|
|
1136
|
-
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
1137
1259
|
VALUE raxis = Qnil, rmin_count = INT2FIX(0), fill_value = Qnil,
|
|
1138
1260
|
method = sym_linear, rkeep = Qfalse;
|
|
1139
1261
|
rb_scan_options(ropt, "axis,min_count,fill_value,method,keep_axis",
|
|
@@ -1141,6 +1263,15 @@ rb_ca_percentile_m (int argc, VALUE *argv, VALUE self)
|
|
|
1141
1263
|
|
|
1142
1264
|
CArray *ca;
|
|
1143
1265
|
GetCArray(self, ca);
|
|
1266
|
+
/* A lazy expression is computed whole here, so a registered evaluator
|
|
1267
|
+
may compute it instead. */
|
|
1268
|
+
{
|
|
1269
|
+
volatile VALUE evaluated = ca_lazy_evaluated(self);
|
|
1270
|
+
if ( ! NIL_P(evaluated) ) {
|
|
1271
|
+
self = evaluated;
|
|
1272
|
+
GetCArray(self, ca);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1144
1275
|
/* Boolean rides the f64 lane (0/1 -> 0.0/1.0), so percentile / quantile
|
|
1145
1276
|
interpolate and return a float, matching the integer lane. */
|
|
1146
1277
|
if ( ca->data_type == CA_BOOLEAN ) {
|
|
@@ -1148,16 +1279,24 @@ rb_ca_percentile_m (int argc, VALUE *argv, VALUE self)
|
|
|
1148
1279
|
GetCArray(self, ca);
|
|
1149
1280
|
}
|
|
1150
1281
|
int8_t dt = ca->data_type;
|
|
1151
|
-
if ( ca_is_fixlen_type(ca) )
|
|
1282
|
+
if ( ca_is_fixlen_type(ca) ) {
|
|
1283
|
+
ca_face_refuse_numeric(self, "percentile", rb_eCADataTypeError);
|
|
1152
1284
|
rb_raise(rb_eCADataTypeError,
|
|
1153
1285
|
"percentile: not defined for fixlen; use a numeric or object array");
|
|
1286
|
+
}
|
|
1154
1287
|
int is_obj = (dt == CA_OBJECT);
|
|
1155
1288
|
if ( !is_obj && !mp_is_numeric(dt) )
|
|
1156
|
-
rb_raise(rb_eCADataTypeError, "percentile:
|
|
1289
|
+
rb_raise(rb_eCADataTypeError, "percentile: source data_type :%s not supported", ca_type_name[dt]);
|
|
1157
1290
|
|
|
1158
|
-
long min_count =
|
|
1159
|
-
|
|
1160
|
-
|
|
1291
|
+
long min_count = ca_min_count_arg(rmin_count, NULL);
|
|
1292
|
+
/* fill_value: UNDEF leaves the result undefined; any other fill is what
|
|
1293
|
+
a store into the float64 result would make of it. */
|
|
1294
|
+
if ( fill_value == CA_UNDEF ) {
|
|
1295
|
+
fill_value = Qnil;
|
|
1296
|
+
}
|
|
1297
|
+
else if ( ! NIL_P(fill_value) && ! is_obj ) {
|
|
1298
|
+
fill_value = ca_fill_as(fill_value, CA_FLOAT64);
|
|
1299
|
+
}
|
|
1161
1300
|
|
|
1162
1301
|
VALUE pers = pct_flatten_validate_pers(rb_ary_new_from_values(argc, argv));
|
|
1163
1302
|
pct_validate_method(method);
|
|
@@ -1175,7 +1314,7 @@ rb_ca_percentile_m (int argc, VALUE *argv, VALUE self)
|
|
|
1175
1314
|
flattened first and follows the same rule (length 1 unwraps). */
|
|
1176
1315
|
VALUE result;
|
|
1177
1316
|
if ( !NIL_P(raxis) ) {
|
|
1178
|
-
long axis = rb_ca_normalize_axis_value(self, raxis,
|
|
1317
|
+
long axis = rb_ca_normalize_axis_value(self, raxis, NULL);
|
|
1179
1318
|
/* mask / min_count / fill_value require the per-fiber select (each fiber
|
|
1180
1319
|
has its own n_present); the plain partition/sort path assumes a
|
|
1181
1320
|
uniform n. These paths bake keep_axis into the reduced output. */
|
|
@@ -1216,11 +1355,18 @@ rb_ca_percentile_m (int argc, VALUE *argv, VALUE self)
|
|
|
1216
1355
|
return result;
|
|
1217
1356
|
}
|
|
1218
1357
|
|
|
1358
|
+
static VALUE
|
|
1359
|
+
rb_ca_percentile_m_body (int argc, VALUE *argv, VALUE self)
|
|
1360
|
+
{
|
|
1361
|
+
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
1362
|
+
return rb_ca_percentile_kw(argc, argv, ropt, self);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1219
1365
|
/* [entry] quantile(axis:, keep_axis:) = percentile(0, 25, 50, 75, 100, ...).
|
|
1220
1366
|
Return shape: Array<Float> len 5 (flat) or Array<CArray> len 5 (per-axis),
|
|
1221
1367
|
matching percentile's multi-p wrapping since we pass 5 fixed p values. */
|
|
1222
1368
|
static VALUE
|
|
1223
|
-
|
|
1369
|
+
rb_ca_quantile_m_body (int argc, VALUE *argv, VALUE self)
|
|
1224
1370
|
{
|
|
1225
1371
|
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
1226
1372
|
if ( argc != 0 )
|
|
@@ -1230,9 +1376,62 @@ rb_ca_quantile_m (int argc, VALUE *argv, VALUE self)
|
|
|
1230
1376
|
VALUE opts = rb_hash_new();
|
|
1231
1377
|
if ( !NIL_P(raxis) ) rb_hash_aset(opts, ID2SYM(rb_intern("axis")), raxis);
|
|
1232
1378
|
rb_hash_aset(opts, ID2SYM(rb_intern("keep_axis")), rkeep);
|
|
1233
|
-
VALUE pa[
|
|
1234
|
-
|
|
1235
|
-
|
|
1379
|
+
VALUE pa[5] = { INT2FIX(0), INT2FIX(25), INT2FIX(50), INT2FIX(75), INT2FIX(100) };
|
|
1380
|
+
return rb_ca_percentile_kw(5, pa, opts, self);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
typedef struct { int argc; VALUE *argv; VALUE self; } mp_median_call_t;
|
|
1385
|
+
|
|
1386
|
+
static VALUE
|
|
1387
|
+
mp_median_answer_body (VALUE p)
|
|
1388
|
+
{
|
|
1389
|
+
mp_median_call_t *c = (mp_median_call_t *) p;
|
|
1390
|
+
return rb_ca_median_m_body(c->argc, c->argv, c->self);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
/* An error raised by the methods this one calls names this one. */
|
|
1394
|
+
static VALUE
|
|
1395
|
+
rb_ca_median_m (int argc, VALUE *argv, VALUE self)
|
|
1396
|
+
{
|
|
1397
|
+
mp_median_call_t c = { argc, argv, self };
|
|
1398
|
+
return ca_answer_as_caller(mp_median_answer_body, (VALUE) &c);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
typedef struct { int argc; VALUE *argv; VALUE self; } mp_percentile_call_t;
|
|
1403
|
+
|
|
1404
|
+
static VALUE
|
|
1405
|
+
mp_percentile_answer_body (VALUE p)
|
|
1406
|
+
{
|
|
1407
|
+
mp_percentile_call_t *c = (mp_percentile_call_t *) p;
|
|
1408
|
+
return rb_ca_percentile_m_body(c->argc, c->argv, c->self);
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/* An error raised by the methods this one calls names this one. */
|
|
1412
|
+
static VALUE
|
|
1413
|
+
rb_ca_percentile_m (int argc, VALUE *argv, VALUE self)
|
|
1414
|
+
{
|
|
1415
|
+
mp_percentile_call_t c = { argc, argv, self };
|
|
1416
|
+
return ca_answer_as_caller(mp_percentile_answer_body, (VALUE) &c);
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
|
|
1420
|
+
typedef struct { int argc; VALUE *argv; VALUE self; } mp_quantile_call_t;
|
|
1421
|
+
|
|
1422
|
+
static VALUE
|
|
1423
|
+
mp_quantile_answer_body (VALUE p)
|
|
1424
|
+
{
|
|
1425
|
+
mp_quantile_call_t *c = (mp_quantile_call_t *) p;
|
|
1426
|
+
return rb_ca_quantile_m_body(c->argc, c->argv, c->self);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/* An error raised by the methods this one calls names this one. */
|
|
1430
|
+
static VALUE
|
|
1431
|
+
rb_ca_quantile_m (int argc, VALUE *argv, VALUE self)
|
|
1432
|
+
{
|
|
1433
|
+
mp_quantile_call_t c = { argc, argv, self };
|
|
1434
|
+
return ca_answer_as_caller(mp_quantile_answer_body, (VALUE) &c);
|
|
1236
1435
|
}
|
|
1237
1436
|
|
|
1238
1437
|
void
|
|
@@ -1242,6 +1441,7 @@ Init_carray_median_percentile (void)
|
|
|
1242
1441
|
id_sort_copy = rb_intern("sort_copy");
|
|
1243
1442
|
id_is_not_masked = rb_intern("is_not_masked");
|
|
1244
1443
|
id_plus = rb_intern("+"); id_div = rb_intern("/"); id_mul = rb_intern("*");
|
|
1444
|
+
id_rationalize = rb_intern("rationalize");
|
|
1245
1445
|
id_min = rb_intern("min"); id_max = rb_intern("max");
|
|
1246
1446
|
id_sort = rb_intern("sort"); id_copy = rb_intern("copy");
|
|
1247
1447
|
id_aref = rb_intern("[]"); id_aset = rb_intern("[]=");
|