Enhancing valarray with "normal" arithmetic operators

  • Thread starter =?ISO-8859-1?Q?Christian_Brechb=FChler?=
  • Start date
?

=?ISO-8859-1?Q?Christian_Brechb=FChler?=

The template std::valarray behaves pretty much like a mathematical
vector. Arithmetic operators apply elementwise. Now I'd like to extend
this to a user-defined type, e.g., complex.

Multiplying a double by a complex number gives a complex number. Now I
would like to multiply a valarray of doubles by a complex number and get
a valarray of complex numbers. Of course, a C++ compiler won't jump to
that conclusion; I need to define something to help it.

I didn't expect the following to compile:

#include <valarray>
#include <complex>
int main()
{
const double a0[] = {1.5, 4, 0};
std::valarray<double> a(a0, 3);
std::complex<double> z(1,2);
std::valarray<std::complex<double> > c (3);
c = z * a; // error: no match for operator *
return 0;
}

And indeed it gives "no match for `std::complex<double>& *
std::valarray<double>&' operator". (BTW, c is irrelevant to the
problem; I just want to show you what I expect.)

Now the question is, what would be the clean way to provide such
functionality? I want to avoid putting any notational burden on the
user. If possible, I'd like to avoid code duplication. Is there a
"generic" approach?

Thanks

Christian
 
R

red floyd

Christian said:
The template std::valarray behaves pretty much like a mathematical
vector. Arithmetic operators apply elementwise. Now I'd like to extend
this to a user-defined type, e.g., complex.

Multiplying a double by a complex number gives a complex number. Now I
would like to multiply a valarray of doubles by a complex number and get
a valarray of complex numbers. Of course, a C++ compiler won't jump to
that conclusion; I need to define something to help it.

I didn't expect the following to compile:

#include <valarray>
#include <complex>
int main()
{
const double a0[] = {1.5, 4, 0};
std::valarray<double> a(a0, 3);
std::complex<double> z(1,2);
std::valarray<std::complex<double> > c (3);
c = z * a; // error: no match for operator *
return 0;
}

And indeed it gives "no match for `std::complex<double>& *
std::valarray<double>&' operator". (BTW, c is irrelevant to the
problem; I just want to show you what I expect.)

Now the question is, what would be the clean way to provide such
functionality? I want to avoid putting any notational burden on the
user. If possible, I'd like to avoid code duplication. Is there a
"generic" approach?

Thanks

Christian

How about simply providing an override on operator* ?:

std::valarray<std::complex<double> >& operator*(double scalar, const
std::valarray<std::complex<double> > &v)
{
return std::complex<double>(scalar) * v);
}

std::valarray<std::complex<double> >& operator*(const
std::valarray<std::complex<double> > &v, double scalar)
{
return std::complex<double>(scalar) * v);
}
}
 
H

Harald Grossauer

Christian Brechbühler wrote:

#include <valarray>
#include <complex>
int main()
{
const double a0[] = {1.5, 4, 0};
std::valarray<double> a(a0, 3);
std::complex<double> z(1,2);
std::valarray<std::complex<double> > c (3);
c = z * a; // error: no match for operator *
return 0;
}

Have you tried to initialize z as double complex valarray with the same
length as a and all values set to (1,2)? I think then z*a should translate
into z*a (i.e. operator*(complex<..>, double)) which should be
defined. But I am certainly not sure about that.
 
?

=?ISO-8859-1?Q?Christian_Brechb=FChler?=

I said:
#include <valarray>
#include <complex>
int main()
{
const double a0[] = {1.5, 4, 0};
std::valarray<double> a(a0, 3);
std::complex<double> z(1,2);
std::valarray<std::complex<double> > c (3);
c = z * a; // error: no match for operator *
return 0;
}

Harald Grossauer replied:
Have you tried to initialize z as double complex valarray with the same
length as a and all values set to (1,2)? I think then z*a should translate
into z*a (i.e. operator*(complex<..>, double)) which should be
defined. But I am certainly not sure about that.


I would have expected that it works, but this approach would put a
notational burden on the client code. I'd prefer to avoid that, i.e.,
I'd like my program, with an additional #include directive, to compile
as written.

To try it out, I changed the definition of z to

std::valarray<std::complex<double> > z(std::complex<double>(1,2), 3);

But this doesn't compile. E.g., g++ complains,

varr-complex-1.cc:10: no match for `valarray<complex<double> > & *
valarray<double> &'
/usr/include/g++-3/std/fcomplex.h:68: candidates are: complex<float>
operator* (const complex<float> &, float)
/usr/include/g++-3/std/fcomplex.h:70: complex<float>
operator* (float, const complex<float> &)
/usr/include/g++-3/std/dcomplex.h:68: complex<double>
operator* (const complex<double> &, double)
/usr/include/g++-3/std/dcomplex.h:70: complex<double>
operator* (double, const complex<double> &)
/usr/include/g++-3/std/ldcomplex.h:68: complex<long
double> operator* (const complex<long double> &, long double)
/usr/include/g++-3/std/ldcomplex.h:70: complex<long

Apparently the STL has specializations for multiplying valarrays of
float, double, and long.

What I would like to express is that any operation (say, + - * /)
applied to a valarray and a scalar of types for which the operation is
defined yields a valarray of the "wider" type. Where, e.g., double is
wider than float, and complex<double> is wider than double. But that
may be outside of what I can express in C++.

BTW, valarray<complex> *= double is defined. But valarray<complex> *
double is NOT.

Vielen Dank für den Vorschlag

Christian
 
?

=?ISO-8859-1?Q?Christian_Brechb=FChler?=

I said:
I would like to multiply a valarray of doubles by a complex number and
get a valarray of complex numbers. Of course, a C++ compiler won't
jump to that conclusion; I need to define something to help it.

I didn't expect the following to compile:

#include <valarray>
#include <complex>
int main()
{
const double a0[] = {1.5, 4, 0};
std::valarray<double> a(a0, 3);
std::complex<double> z(1,2);
std::valarray<std::complex<double> > c (3);
c = z * a; // error: no match for operator *
return 0;
}
Now the question is, what would be the clean way to provide such
functionality? I want to avoid putting any notational burden on the
user. If possible, I'd like to avoid code duplication. Is there a
"generic" approach?

red floyd replied (his/her corrections applied):
How about simply providing an override on operator* ?:

std::valarray<std::complex<double> >& operator*(double scalar, const
std::valarray<std::complex<double> > &v)
{
return std::complex<double>(scalar) * v;
}

std::valarray<std::complex<double> >& operator*(const
std::valarray<std::complex<double> > &v, double scalar)
{
return std::complex<double>(scalar) * v;
}

Thanks, that works with some adaptation. I wanted to multiply
complex<T> * valarray<T>; the above defines T * valarray<complex<T> > (T
being double). So if insert the adapted code

std::valarray<std::complex<double> >& operator*
(std::complex<double> scalar,
const std::valarray<double> &v)
{
return std::complex<double>(scalar) * v;
}

my program compiles. I can make it a little more generic,

template<class T>
std::valarray<std::complex<T> >& operator*(std::complex<T> scalar,
const std::valarray<T> &v)
{
return std::complex<T>(scalar) * v;
}

(BTW, in the C++ lingo, that would be called (operator) overloading;
overriding means redefining an inherited virtual function in a derived
class.) But I see some drawbacks with this solution:

(A) *Genericity*

As you show, I'd have to define both real * valarray<complex> and
valarray<complex> * real. As alluded, I'll need the same pair for
complex * valarray<real>.

I'd need to type the same set for every operator (at least +, -, *, /).

When I want to use some other types besides complex, I'd have to repeat
everything for each such type. I think it should be possible to write a
template<class A, class B> and specify that A Op_ valarray<B> gives a
valarray<Larger_Of<A,B> >.

(B) *Efficiency*

Multiplying real * complex takes 2 multiplications (of real numbers).
By converting to the scalar to comples, we trade that in for 4
multiplications and 2 additions; this happens for every element of the
valarray.

Correct me if I'm mistaken, but it looks like this operator* creates a
temporary valarray, passing it by reference to the caller, which then
copies all the values into the receiving valarray. The standard library
seems to use closures to avoid such copying.


It's generally considered BAD to use preprocessor macros in C++. Can we
do without? It seems not even the standard templates can. In
<valarray>, I see this:

#define _DEFINE_BINARY_OPERATOR(_Op, _Name) \
template<typename _Tp> \
inline _Expr<_BinClos<_Name,_ValArray,_ValArray,_Tp,_Tp>, _Tp> \
operator _Op (const valarray<_Tp> &__v, const valarray<_Tp> &__w) \
// [omitted 20 lines defining this and two other operators]
}

_DEFINE_BINARY_OPERATOR(+, plus)
_DEFINE_BINARY_OPERATOR(-, minus)
_DEFINE_BINARY_OPERATOR(*, multiplies)
_DEFINE_BINARY_OPERATOR(/, divides)
_DEFINE_BINARY_OPERATOR(%, modulus)
_DEFINE_BINARY_OPERATOR(^, _Bitwise_xor)
_DEFINE_BINARY_OPERATOR(&, _Bitwise_and)
_DEFINE_BINARY_OPERATOR(|, _Bitwise_or)
_DEFINE_BINARY_OPERATOR(<<, _Shift_left)
_DEFINE_BINARY_OPERATOR(>>, _Shift_right)

#undef _DEFINE_BINARY_OPERATOR

Well, there's the answer to not having to retype everything for every
operator. And it gives the optimizations of a closure.

The question stays, is this a reasonable approach for my own types? Can
it be templated so it works for adding int to double just like for
multiplying complex<double> with double? Could this feat be achieved
without preprocessor macros?

Christian
 
?

=?ISO-8859-1?Q?Christian_Brechb=FChler?=

I said:
I would like to multiply a valarray of doubles by a complex number
and get a valarray of complex numbers. [...]
What would be the clean way to provide such functionality?

red floyd replied (his/her corrections applied):
How about simply providing an override on operator* ?:

std::valarray<std::complex<double> >& operator*(double scalar, const
std::valarray<std::complex<double> > &v)
{
return std::complex<double>(scalar) * v;
}

std::valarray<std::complex<double> >& operator*(const
std::valarray<std::complex<double> > &v, double scalar)
{
return std::complex<double>(scalar) * v;
}


Thanks, that works with some adaptation. I wanted to multiply
complex<T> * valarray<T>; the above defines T * valarray<complex<T> > (T
being double). So if insert the adapted code

std::valarray<std::complex<double> >& operator*
(std::complex<double> scalar,
const std::valarray<double> &v)
{
return std::complex<double>(scalar) * v;
}

my program compiles.

Ooops, that was naive: this is simply an infinite recursion! (Yes it
compiles :) )
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top