simd 0.0.1 → 0.1.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
  SHA1:
3
- metadata.gz: 11df730f8e1819314d0c0cdf188b24a01e0939cf
4
- data.tar.gz: 35be81c3b191dc4b12d587145535813aef3c2e5b
3
+ metadata.gz: 8f0bff704f3580fee55205c32ada6a1844dde4ae
4
+ data.tar.gz: 9e4f9d097fa20a349b77279535d39ea695a881a4
5
5
  SHA512:
6
- metadata.gz: 1d02246e5e09becf5f301803cc97a6756a93ae8d6d7858b0218adca7d688573892bbd7e83325c277dee65663e5168f570d8f220d75fa7c81098a8b9d490b8370
7
- data.tar.gz: bdd5f50f1e590f839a3067761ad0c865b831e3e97002f2155168f943e9b1258e5f0cc95e6b9481074954865e09c99e2e28ceaeb19480184e4ddf4b9a58b406db
6
+ metadata.gz: ccaa110b5ff7708c5e14dd5355f4361544832b412c2d150e9849f8106c55e1183252cbe540163941b65968037369b8618b5e66c9267e75807553aa2e7e8ccda5
7
+ data.tar.gz: e107fe3e242f6baa6d93ab6edf2886f58499d70fd690f6f1c72d7bff165932ce953026d480b0ac3a41c5e35d1ec4dc8b96c19d38d19857f0fdc8c7e759c3fa44
@@ -2,87 +2,123 @@
2
2
 
3
3
  VALUE SIMD_FloatArray = Qnil;
4
4
 
5
+ /* Internal: Create the SIMD::FloatArray class. */
5
6
  void Init_SIMD_FloatArray(VALUE parent)
6
7
  {
7
8
  SIMD_FloatArray = rb_define_class_under(parent, "FloatArray", rb_cObject);
8
9
  rb_define_alloc_func(SIMD_FloatArray, allocate);
9
10
  rb_define_method(SIMD_FloatArray, "initialize", method_initialize, 1);
10
11
  rb_define_method(SIMD_FloatArray, "*", method_multiply, 1);
12
+ rb_define_method(SIMD_FloatArray, "/", method_divide, 1);
13
+ rb_define_method(SIMD_FloatArray, "+", method_add, 1);
14
+ rb_define_method(SIMD_FloatArray, "-", method_subtract, 1);
11
15
  rb_define_method(SIMD_FloatArray, "length", method_length, 0);
12
16
  rb_define_method(SIMD_FloatArray, "to_a", method_to_a, 0);
13
17
  }
14
18
 
19
+ /* Internal: Allocate memory for the vector container. */
15
20
  static VALUE allocate(VALUE klass)
16
21
  {
17
- double_vector_wrapper *vector = malloc(sizeof(double_vector_wrapper));
18
- vector->data = NULL;
22
+ d2v_container *vector = malloc(sizeof(d2v_container));
23
+ if(vector == NULL)
24
+ {
25
+ rb_raise(rb_eNoMemError, "Unable to allocate memory");
26
+ }
19
27
 
28
+ vector->data = NULL; /* Avoid potentially freeing unitialized memory. */
20
29
  return(Data_Wrap_Struct(klass, NULL, deallocate, vector));
21
30
  }
22
31
 
23
- static void deallocate(double_vector_wrapper *vector)
32
+ /* Internal: Free memory from the vector container and the data array. */
33
+ static void deallocate(d2v_container *vector)
24
34
  {
25
- free(vector);
35
+ if(vector)
36
+ {
37
+ if(vector->data)
38
+ {
39
+ free(vector->data);
40
+ }
41
+ free(vector);
42
+ }
26
43
  }
27
44
 
45
+ /* Public: Initialize the FloatArray object given a Ruby Array of values
46
+ * which can be cast to a double. */
28
47
  static VALUE method_initialize(VALUE self, VALUE rb_array)
29
48
  {
30
- double_vector_wrapper *vector;
31
- long n,m,i;
49
+ d2v_container *vector;
50
+ unsigned long n,m,i;
32
51
 
33
52
  Check_Type(rb_array, T_ARRAY);
53
+ Data_Get_Struct(self, d2v_container, vector);
34
54
 
35
- Data_Get_Struct(self, double_vector_wrapper, vector);
36
55
  vector->len = n = RARRAY_LEN(rb_array);
37
- m = n + (n % 2);
38
- vector->data = malloc(((m / 2) * sizeof(d2v_t)));
56
+
57
+ if(vector->len < 2)
58
+ {
59
+ rb_raise(rb_eArgError, "Vectors must be at least 2 long");
60
+ }
61
+
62
+ vector->data = internal_allocate_vector_array(vector->len);
39
63
 
40
64
  for(i = 0; i < n; i++)
41
65
  vector->data[i/2].f[i%2] = NUM2DBL(rb_ary_entry(rb_array, i));
42
66
 
67
+ /* If the array is an odd number of elements, set the final element to 1 */
68
+ m = n + (n % 2);
43
69
  if(n < m)
70
+ {
44
71
  vector->data[m/2].f[1] = 1.0;
72
+ }
45
73
 
46
74
  return(self);
47
75
  }
48
76
 
77
+ /* Public: Multiply values contained in the data array with those contained in
78
+ * another FloatArray object, returning a new FloatArray. */
49
79
  static VALUE method_multiply(VALUE self, VALUE obj)
50
80
  {
51
- long size, i;
52
- double_vector_wrapper *vector, *vector2, *result;
53
-
54
- Data_Get_Struct(self, double_vector_wrapper, vector);
55
- Data_Get_Struct(obj, double_vector_wrapper, vector2);
56
-
57
- if(vector->len != vector2->len && vector2->len != 2)
58
- rb_raise(rb_eArgError, "Vectors must be the same size, or 2.");
81
+ return(internal_apply_operation(self, obj, func_multiply));
82
+ }
59
83
 
60
- size = vector->len + (vector->len % 2);
61
- result = malloc(sizeof(double_vector_wrapper));
62
- result->data = malloc(size * sizeof(d2v_t));
63
- result->len = vector->len;
84
+ /* Public: Divide values contained in the data array by those contained in
85
+ * another FloatArray object, returning a new FloatArray. */
86
+ static VALUE method_divide(VALUE self, VALUE obj)
87
+ {
88
+ return(internal_apply_operation(self, obj, func_divide));
89
+ }
64
90
 
65
- for(i = 0; i < size / 2; i++)
66
- result->data[i].v = vector->data[i].v * vector2->data[i].v;
91
+ /* Public: add values contained in the data array with those contained in
92
+ * another FloatArray object, returning a new FloatArray. */
93
+ static VALUE method_add(VALUE self, VALUE obj)
94
+ {
95
+ return(internal_apply_operation(self, obj, func_add));
96
+ }
67
97
 
68
- return(Data_Wrap_Struct(SIMD_FloatArray, NULL, deallocate, result));
98
+ /* Public: Subtract values contained in another FloatArray object from those
99
+ * contained in the current data array object, returning a new FloatArray. */
100
+ static VALUE method_subtract(VALUE self, VALUE obj)
101
+ {
102
+ return(internal_apply_operation(self, obj, func_subtract));
69
103
  }
70
104
 
105
+ /* Public: Return the number of elements in the Array. */
71
106
  static VALUE method_length(VALUE self)
72
107
  {
73
- double_vector_wrapper *vector;
74
- Data_Get_Struct(self, double_vector_wrapper, vector);
108
+ d2v_container *vector;
109
+ Data_Get_Struct(self, d2v_container, vector);
75
110
 
76
111
  return(INT2NUM(vector->len));
77
112
  }
78
113
 
114
+ /* Public: Return a Ruby Array containing the doubles within the data array. */
79
115
  static VALUE method_to_a(VALUE self)
80
116
  {
81
- long i;
82
- double_vector_wrapper *vector;
117
+ unsigned long i;
118
+ d2v_container *vector;
83
119
  VALUE rb_array = rb_ary_new();
84
120
 
85
- Data_Get_Struct(self, double_vector_wrapper, vector);
121
+ Data_Get_Struct(self, d2v_container, vector);
86
122
  for(i = 0; i < vector->len; i++)
87
123
  {
88
124
  rb_ary_store(rb_array, i, DBL2NUM(vector->data[i/2].f[i%2]));
@@ -90,3 +126,110 @@ static VALUE method_to_a(VALUE self)
90
126
 
91
127
  return(rb_array);
92
128
  }
129
+
130
+ /* Internal: Given another FloatArray object, perform an action specified via a
131
+ * function pointer against both. */
132
+ static VALUE internal_apply_operation(VALUE self, VALUE obj, b_operation func)
133
+ {
134
+ unsigned long size, i;
135
+ int align;
136
+ d2v_container *v1, *v2, *r;
137
+ VALUE result_obj = allocate(SIMD_FloatArray);
138
+
139
+ Data_Get_Struct(self, d2v_container, v1);
140
+ Data_Get_Struct(obj, d2v_container, v2);
141
+ Data_Get_Struct(result_obj, d2v_container, r);
142
+
143
+ align = internal_align_vectors(v1->len, v2->len);
144
+
145
+ /* Ensure that size will be the result of ceil(len / 2.0) */
146
+ size = (v1->len + 1) / 2;
147
+ r->data = internal_allocate_vector_array(v1->len);
148
+ r->len = v1->len;
149
+
150
+ switch(align)
151
+ {
152
+ case 0: /* Same size arrays */
153
+ for(i = 0; i < size; i++)
154
+ {
155
+ r->data[i].v = func(v1->data[i].v, v2->data[i].v);
156
+ }
157
+ break;
158
+ case 1: /* Operand is exactly 2 long (size of 1 sse register) */
159
+ for(i = 0; i < size; i++)
160
+ {
161
+ r->data[i].v = func(v1->data[i].v, v2->data[0].v);
162
+ }
163
+ break;
164
+ default: /* Self is a multiple of operand's length long */
165
+ for(i = 0; i < size; i++)
166
+ {
167
+ r->data[i].v = func(v1->data[i].v, v2->data[i % v2->len].v);
168
+ }
169
+ }
170
+
171
+ return(result_obj);
172
+ }
173
+
174
+ /* Internal: Allocate memory for the data array. */
175
+ static d2v_t *internal_allocate_vector_array(unsigned long size)
176
+ {
177
+ d2v_t *vector = malloc(((size + (size % 2)) / 2 + 1) * sizeof(d2v_t));
178
+ if(vector == NULL)
179
+ {
180
+ rb_raise(rb_eNoMemError, "Unable to allocate memory");
181
+ }
182
+
183
+ return(vector);
184
+ }
185
+
186
+ /* Internal: Determine if two arrays can be acted upon, by being of equal
187
+ * lengths or with the operand's length being a multiple of the data array's. */
188
+ static int internal_align_vectors(unsigned long v1, unsigned long v2)
189
+ {
190
+ if((v1 % 2) != (v2 % 2))
191
+ {
192
+ rb_raise(rb_eArgError, "Both Vectors must be of even or odd length.");
193
+ }
194
+
195
+ if(v1 == v2)
196
+ {
197
+ return(0);
198
+ }
199
+ if(v2 == 2)
200
+ {
201
+ return(1);
202
+ }
203
+ if(v1 % v2 == 0)
204
+ {
205
+ return(2);
206
+ }
207
+
208
+ rb_raise(rb_eArgError, "Vector length must be evenly divisible by operand.");
209
+ /* Never reached */
210
+ return(-1);
211
+ }
212
+
213
+ /* Function: Multiply two vectors. */
214
+ static d2v func_multiply(d2v v1, d2v v2)
215
+ {
216
+ return(v1 * v2);
217
+ }
218
+
219
+ /* Function: Divide two vectors. */
220
+ static d2v func_divide(d2v v1, d2v v2)
221
+ {
222
+ return(v1 / v2);
223
+ }
224
+
225
+ /* Function: Add two vectors. */
226
+ static d2v func_add(d2v v1, d2v v2)
227
+ {
228
+ return(v1 + v2);
229
+ }
230
+
231
+ /* Function: Subtract two vectors. */
232
+ static d2v func_subtract(d2v v1, d2v v2)
233
+ {
234
+ return(v1 - v2);
235
+ }
@@ -1,22 +1,22 @@
1
1
  #include "ruby.h"
2
-
3
- typedef double __attribute__ ((vector_size (16))) v2d;
4
- typedef union d2v_t
5
- {
6
- v2d v;
7
- double f[2];
8
- } d2v_t;
9
-
10
- typedef struct double_vector_wrapper
11
- {
12
- d2v_t *data;
13
- long len;
14
- } double_vector_wrapper;
2
+ #include "simd_types.h"
15
3
 
16
4
  static VALUE allocate(VALUE klass);
17
- static void deallocate(double_vector_wrapper *floatarray);
5
+ static void deallocate(d2v_container *floatarray);
18
6
 
19
7
  static VALUE method_initialize(VALUE self, VALUE rb_array);
20
8
  static VALUE method_multiply(VALUE self, VALUE obj);
9
+ static VALUE method_divide(VALUE self, VALUE obj);
10
+ static VALUE method_add(VALUE self, VALUE obj);
11
+ static VALUE method_subtract(VALUE self, VALUE obj);
21
12
  static VALUE method_length(VALUE self);
22
13
  static VALUE method_to_a(VALUE self);
14
+
15
+ static d2v_t *internal_allocate_vector_array(unsigned long size);
16
+ static int internal_align_vectors(unsigned long v1, unsigned long v2);
17
+ static VALUE internal_apply_operation(VALUE self, VALUE obj, b_operation func);
18
+
19
+ static d2v func_multiply(d2v v1, d2v v2);
20
+ static d2v func_divide(d2v v1, d2v v2);
21
+ static d2v func_add(d2v v1, d2v v2);
22
+ static d2v func_subtract(d2v v1, d2v v2);
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Types for FloatArray
3
+ *
4
+ * Since ruby internally uses doubles for the Float type, SIMD::FloatArray will
5
+ * use packed double operations by default.
6
+ */
7
+ typedef double __attribute__ ((vector_size (16))) d2v;
8
+ typedef union d2v_t
9
+ {
10
+ d2v v;
11
+ double f[2];
12
+ } d2v_t;
13
+
14
+ typedef struct d2v_container
15
+ {
16
+ d2v_t *data;
17
+ unsigned long len;
18
+ } d2v_container;
19
+
20
+ typedef d2v (*b_operation)(d2v v1, d2v v2);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina Wuest
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-09 00:00:00.000000000 Z
11
+ date: 2014-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -36,6 +36,7 @@ files:
36
36
  - ext/simd/simd.h
37
37
  - ext/simd/simd_floatarray.c
38
38
  - ext/simd/simd_floatarray.h
39
+ - ext/simd/simd_types.h
39
40
  homepage: https://gitlab.com/wuest/simd-ruby
40
41
  licenses: []
41
42
  metadata: {}