# Extending NArray

**URL:** <https://www.ruby-forum.com/t/extending-narray/65963>\
**Category:** Ruby\
**Created:** [February 11, 2006, 10:13pm UTC](https://www.ruby-forum.com/t/extending-narray/65963 "2006-02-11T22:13:24Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Cameron\_McBride](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a87d85/32.png) [@Cameron\_McBride](https://www.ruby-forum.com/u/Cameron_McBride)\
**Post date:** [February 11, 2006, 10:13pm UTC](https://www.ruby-forum.com/t/extending-narray/65963/1 "2006-02-11T22:13:24Z")

</div>

I’m trying to make the fast extensions to NArray, yet still preserve  
the general nature of methods (i.e. works on all NArray types). As an  
example, I’ll show benchmarks of a simple weighted mean:

Benchmarking based:  
num\_runs = 1000  
data\_size = 100000  
user system total real  
NArray\_rb 3.150000 0.660000 3.810000 ( 3.803652)  
NArray\_mod 3.930000 0.020000 3.950000 ( 3.949027)  
NArray\_dbl 1.040000 0.000000 1.040000 ( 1.039897)  
GSL 1.670000 0.000000 1.670000 ( 1.665538)

(sorry, Gmail messed with the formating on paste)

I did the quick NArray\_dbl hack, which is fast but explicitly casts to  
‘double’, so it’s not general. When I generalized it using some  
internal SetFuncs of NArray, the result is slower than a ruby version  
that does a double loop (two #sum calls).

What am I missing? As a success meter, I’d like it to be at least as  
fast as GSL libs.

(benchmark and code attached. additionally uses inline and rb-gsl)

Thanks!

Cameron

---

<div class="post-metadata">

**Author:** ![Cameron\_McBride](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a87d85/32.png) [@Cameron\_McBride](https://www.ruby-forum.com/u/Cameron_McBride)\
**Post date:** [February 13, 2006, 3:45am UTC](https://www.ruby-forum.com/t/extending-narray/65963/2 "2006-02-13T03:45:23Z")

</div>

|From: Cameron McBride

> NArray\_dbl 1.040000 0.000000 1.040000 ( 1.039897)  
> GSL 1.670000 0.000000 1.670000 ( 1.665538)

> I did the quick NArray\_dbl hack, which is fast but explicitly casts to  
> ‘double’, so it’s not general. When I generalized it using some  
> internal SetFuncs of NArray, the result is slower than a ruby version  
> that does a double loop (two #sum calls).
> 
> What am I missing? As a success meter, I’d like it to be at least as  
> fast as GSL libs.

This is probably because a function (SetFuncs) is called  
every step of the loop. How about using na\_change\_type() ?

```
VALUE
wmean_dbl(int argc, VALUE *argv, VALUE self) {

  int i;
  struct NARRAY *nv, *nw;
  double p_sum = 0.0, w_sum = 0.0;
  VALUE vself, varg0;

  vself = na_change_type(self, NA_DFLOAT);
  varg0 = na_change_type(argv[0], NA_DFLOAT);

  GetNArray(vself, nv);
  GetNArray(varg0, nw);

  if(nv->total != nw->total)
    rb_raise( rb_eArgError, "Vector and weight must be same size!" 

```

);

```
  for(i=0 ; i < nv->total ; i++) {
    p_sum += ((double *)nw->ptr)[i] * ((double *)nv->ptr)[i];
    w_sum += ((double *)nw->ptr)[i];
  }

  return rb_float_new( p_sum / w_sum);
}

```

Masahiro Tanaka

---

<div class="post-metadata">

**Author:** ![Cameron\_McBride](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a87d85/32.png) [@Cameron\_McBride](https://www.ruby-forum.com/u/Cameron_McBride)\
**Post date:** [February 13, 2006, 8:15am UTC](https://www.ruby-forum.com/t/extending-narray/65963/3 "2006-02-13T08:15:18Z")

</div>

Thank you for your response, Tanaka-san.

On 2/12/06, Masahiro TANAKA [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> This is probably because a function (SetFuncs) is called  
> every step of the loop. How about using na\_change\_type() ?

Your suggestion is very fast when the types are matched, but if the  
original is not a double, the penalty for copying the array is  
significant. Also, it’s incorrect if the type cannot be represented  
as a float (e.g. complex). (see benchmarks below)

I appreciate the general nature on the design of NArray, and I’ve  
learned several nice tricks from investigating it. However, the moral  
I’m taking home is that if speed, efficiency and generality are all at  
issue, individual routines for each NArray type are still the best way  
to go at the C level.

To build extensions with one algorithm description, it seems the best  
way is some macro type pseudo C code that can be parsed to generate  
multiple C functions for each type. Do you agree?

This seems to justify the approach of the PDL project (perl) and the  
PP language that is employed for general extensions. (and I was so  
hoping to keep this at the straight forward C level to exploit the  
beauty of ruby’s C API. ahh well - it is just C).

Any additional comments or suggestions are welcome, I’d love to find  
something I missed.

Thanks!

Cameron

* * *

# Benchmarking based on: num\_runs = 1000 data\_size = 100000

==\> INT \<==  
creating vectors: NArray.int(data\_size).random!(100)

```
              user system total real

```

# NArray\_rb 1.050000 0.410000 1.460000 ( 1.459850) NArray\_mod 2.670000 0.030000 2.700000 ( 2.706433) NArray\_ct 2.220000 1.600000 3.820000 ( 3.819964)

==\> SFLOAT \<==  
creating vectors: NArray.sfloat(data\_size).random!(100)

```
              user system total real

```

# NArray\_rb 2.590000 0.340000 2.930000 ( 2.928844) NArray\_mod 2.440000 0.020000 2.460000 ( 2.467045) NArray\_ct 2.100000 1.610000 3.710000 ( 3.715267)

==\> FLOAT \<==  
creating vectors: NArray.float(data\_size).random!(100)

```
              user system total real

```

# NArray\_rb 2.800000 0.800000 3.600000 ( 3.605653) NArray\_mod 3.920000 0.010000 3.930000 ( 3.934259) NArray\_ct 1.020000 0.000000 1.020000 ( 1.026064)

==\> COMPLEX \<==  
creating vectors: NArray.complex(data\_size).random!(100)

```
              user system total real

```

NArray\_rb 5.970000 1.420000 7.390000 ( 7.390152)  
NArray\_mod 3.950000 0.020000 3.970000 ( 3.971336)  
NArray\_ct 2.820000 1.590000 4.410000 ( 4.411596)
