ruby_native_statistics 0.8.2 → 0.9.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58cae049ef922fead26f20dff3714c2f9c1bcccd95fe38228add9d7f6d57e787
4
- data.tar.gz: 3529205f8a822cc3c418d54d36d4651708384cc885f990517e03fc0f1c8edb15
3
+ metadata.gz: b99d6ace1e36cdd53315356b8c4de080289a46bc307b41bc1979de4cbaff2e42
4
+ data.tar.gz: 5b8c3498b2a3014313b0b249eb87350e7f07e5a22237de4ea9e95f67096572c7
5
5
  SHA512:
6
- metadata.gz: fe760b4680dbf1d11685404718589c7d24c659d086c422977ee3e8c1223073331dfb125c83275a9254ce7fa161b33b388cd66008f6de429417c0ba92acedad87
7
- data.tar.gz: 768f2745a827ffa45fe34a89ff7eb4cc1f4d444bfa6c99f2c4bcd75058131b25cfc17f93ee58599511f8e6a265335af7480dc7890988c8e10e5aa318f4d4514c
6
+ metadata.gz: c837f3f6f7e2a8d47291d1e289d09e48de81c5216bca319e1be24aca7a821f0ba8e1acd3548ccfbe83a50b92752af5dc281a9a69dc052e58cee1f5e49b05e06d
7
+ data.tar.gz: 3c8e3629ffe57bccdbdeaa8b792d593aa89bdce401e034a2a0d08fdf62fb1ad0841229cc60c222aaa37fe0895c2fdee83109176ec553e0c1529c33814868fa4e
@@ -27,7 +27,7 @@ jobs:
27
27
  uses: actions/checkout@master
28
28
 
29
29
  - name: Install Bundler
30
- run: gem install bundler -v 2.1.2
30
+ run: gem install bundler --version 2.1.2 --no-document
31
31
 
32
32
  - name: Install gems
33
33
  run: bundle
@@ -0,0 +1,21 @@
1
+ {
2
+ "configurations": [
3
+ {
4
+ "name": "Mac",
5
+ "includePath": [
6
+ "${workspaceFolder}/**",
7
+ "/Users/corybuecker/.asdf/installs/ruby/2.7.0/include/ruby-2.7.0",
8
+ "/Users/corybuecker/.asdf/installs/ruby/2.7.0/include/ruby-2.7.0/x86_64-darwin19"
9
+ ],
10
+ "defines": [],
11
+ "macFrameworkPath": [
12
+ "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
13
+ ],
14
+ "compilerPath": "/usr/bin/clang",
15
+ "cStandard": "c11",
16
+ "cppStandard": "c++17",
17
+ "intelliSenseMode": "clang-x64"
18
+ }
19
+ ],
20
+ "version": 4
21
+ }
data/README.md CHANGED
@@ -6,11 +6,12 @@ This is a native extension to Ruby that adds native (C) statistical functions to
6
6
  - [Population Standard Deviation](https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation) (stdevp)
7
7
  - [Sample Variance](https://en.wikipedia.org/wiki/Variance#Population_variance_and_sample_variance) (var)
8
8
  - [Population Variance](https://en.wikipedia.org/wiki/Variance#Population_variance_and_sample_variance) (varp)
9
+ - [Median](https://en.wikipedia.org/wiki/Median) (median)
9
10
  - [Mean](https://en.wikipedia.org/wiki/Arithmetic_mean) (mean)
10
11
 
11
- Check the CircleCI build to see the currently supported versions of Ruby. This list will match whatever stable versions are specified at https://www.ruby-lang.org/en/downloads/.
12
+ Check the Github Actions build to see the currently supported versions of Ruby. This list will match whatever stable versions are specified at https://www.ruby-lang.org/en/downloads/.
12
13
 
13
- It is much more performant than calculating the standard deviation with pure Ruby. For a comparison, run the benchmarks with rake.
14
+ It is much more performant than calculating the standard deviation with pure Ruby. For a comparison, run the benchmarks with `rake benchmark`.
14
15
 
15
16
  bench_native_dispersion 0.000425 0.000341 0.000420 0.000324 0.000319
16
17
  bench_ruby_dispersion 0.002168 0.002156 0.002148 0.002149 0.002151
@@ -29,6 +30,9 @@ It is much more performant than calculating the standard deviation with pure Rub
29
30
  # calculate mean
30
31
  p r.mean
31
32
 
33
+ # calculate median
34
+ p r.median
35
+
32
36
  ## Links
33
37
 
34
38
  This is the third version of this gem, and it is a total rewrite of a SWIG-based design. Lots of thanks to the following resources:
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ Rake::TestTask.new(:test) do |t|
15
15
  t.test_files = FileList["test/**/*_test.rb"]
16
16
  end
17
17
 
18
- Rake::TestTask.new(:benchmark) do |t|
18
+ Rake::TestTask.new(benchmark: :compile) do |t|
19
19
  t.libs << "test"
20
20
  t.libs << "lib"
21
21
  t.test_files = FileList["test/**/*_benchmark.rb"]
data/changelog.md CHANGED
@@ -1,3 +1,7 @@
1
+ # Version 0.9.0
2
+
3
+ - Add median function
4
+
1
5
  # Version 0.8.2
2
6
 
3
7
  - Bug fix for build process
@@ -1,17 +1,22 @@
1
+ #include "stdbool.h"
1
2
  #include "ruby.h"
2
3
  #include "mathematics.h"
3
4
 
4
- void Init_mathematics() {
5
+ void Init_mathematics()
6
+ {
5
7
  MathematicsModule = rb_define_module("Mathematics");
6
8
  rb_define_method(MathematicsModule, "mean", rb_mean, 0);
9
+ rb_define_method(MathematicsModule, "median", rb_median, 0);
7
10
  }
8
11
 
9
- double calculate_mean(VALUE array, unsigned long array_length){
12
+ double calculate_mean(VALUE array, unsigned long array_length)
13
+ {
10
14
  unsigned long i;
11
15
  double total = 0;
12
16
  double mean = 0;
13
17
 
14
- for(i = 0; i < array_length; i++){
18
+ for (i = 0; i < array_length; i++)
19
+ {
15
20
  total += rb_num2dbl(rb_ary_entry(array, i));
16
21
  }
17
22
 
@@ -20,31 +25,103 @@ double calculate_mean(VALUE array, unsigned long array_length){
20
25
  return mean;
21
26
  }
22
27
 
23
- double calculate_total_distance_from_mean(VALUE array, unsigned long array_length){
28
+ double calculate_total_distance_from_mean(VALUE array, unsigned long array_length)
29
+ {
24
30
  unsigned long i;
25
31
  double mean = 0;
26
32
  double total_distance_from_mean = 0;
27
33
 
28
34
  mean = calculate_mean(array, array_length);
29
35
 
30
- for(i = 0; i < array_length; i++){
36
+ for (i = 0; i < array_length; i++)
37
+ {
31
38
  total_distance_from_mean += pow((rb_num2dbl(rb_ary_entry(array, i)) - mean), 2);
32
39
  }
33
40
 
34
41
  return total_distance_from_mean;
35
42
  }
36
43
 
37
- VALUE rb_mean(VALUE self) {
44
+ VALUE rb_mean(VALUE self)
45
+ {
38
46
  unsigned int array_length;
39
47
 
40
48
  Check_Type(self, T_ARRAY);
41
49
 
42
50
  array_length = rb_long2int(RARRAY_LEN(self));
43
51
 
44
- if (array_length <= 0) {
52
+ if (array_length <= 0)
53
+ {
45
54
  rb_raise(rb_eRangeError, "array must have at least one element");
46
55
  }
47
56
 
48
57
  return DBL2NUM(calculate_mean(self, array_length));
49
58
  }
50
59
 
60
+ int compare_doubles(const void *a, const void *b)
61
+ {
62
+ double *dbl_a = (double *)a;
63
+ double *dbl_b = (double *)b;
64
+
65
+ double cmp_a = *dbl_a;
66
+ double cmp_b = *dbl_b;
67
+
68
+ return (cmp_a - cmp_b);
69
+ }
70
+
71
+ VALUE rb_median(VALUE self)
72
+ {
73
+ unsigned long array_length;
74
+ unsigned long i;
75
+ double *working_array;
76
+ VALUE result;
77
+
78
+ Check_Type(self, T_ARRAY);
79
+
80
+ array_length = RARRAY_LEN(self);
81
+
82
+ if (array_length <= 0)
83
+ {
84
+ rb_raise(rb_eRangeError, "array must have at least one element");
85
+ }
86
+
87
+ bool array_even_size = (array_length % 2) == 0;
88
+ unsigned long middle = (long)floor(array_length / 2.0);
89
+
90
+ working_array = malloc(array_length * sizeof(double));
91
+
92
+ if (working_array == NULL)
93
+ {
94
+ rb_raise(rb_eStandardError, "unknown problem calculating median (possibly array is too large)");
95
+ }
96
+
97
+ for (i = 0; i < array_length; i++)
98
+ {
99
+ VALUE item = rb_ary_entry(self, i);
100
+
101
+ if (!RB_INTEGER_TYPE_P(item) && !RB_FLOAT_TYPE_P(item))
102
+ {
103
+ free(working_array);
104
+ rb_raise(rb_eTypeError, "element is not a number");
105
+ }
106
+
107
+ working_array[i] = NUM2DBL(item);
108
+ }
109
+
110
+ // Reminder to myself as I'm learning C. Using an array as a function parameter decays that reference
111
+ // to a pointer to the first element in the array.
112
+ // https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Function-Parameters
113
+ qsort(working_array, array_length, sizeof(double), compare_doubles);
114
+
115
+ if (!array_even_size)
116
+ {
117
+ result = DBL2NUM(working_array[middle]);
118
+ }
119
+ else
120
+ {
121
+ result = DBL2NUM((working_array[middle - 1] + working_array[middle]) / 2);
122
+ }
123
+
124
+ free(working_array);
125
+
126
+ return result;
127
+ }
@@ -1,4 +1,5 @@
1
1
  VALUE MathematicsModule = Qnil;
2
2
  VALUE rb_mean(VALUE self);
3
+ VALUE rb_median(VALUE self);
3
4
  double calculate_mean(VALUE array, unsigned long array_length);
4
5
  double calculate_total_distance_from_mean(VALUE array, unsigned long array_length);
@@ -1,3 +1,3 @@
1
1
  module RubyNativeStatistics
2
- VERSION = "0.8.2"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_native_statistics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cory Buecker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-11 00:00:00.000000000 Z
11
+ date: 2020-01-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -21,6 +21,7 @@ extra_rdoc_files: []
21
21
  files:
22
22
  - ".github/workflows/main.yml"
23
23
  - ".gitignore"
24
+ - ".vscode/c_cpp_properties.json"
24
25
  - ".vscode/settings.json"
25
26
  - Gemfile
26
27
  - Gemfile.lock