simd 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: {}