开发者

Set double[] from float* in initialization list

开发者 https://www.devze.com 2023-03-23 03:15 出处:网络
I have a class that looks roughly like this: template<std::size_t dim> class Foo { public: Foo(void const * const data);

I have a class that looks roughly like this:

template<std::size_t dim>
class Foo {
public:
    Foo(void const * const data);
private: 
    double vals[dim];
}

For the constructor, I know that void* data points to an array of float values (of dimension dim). Now I would like to initialize the vals-array (preferably) in the initialization list of that constructor.

开发者_如何学编程

To make matters worse, the floats pointed to do not necessarily have to be memory-aligned properly.

How could I do this efficiently?


Edit 1

With respect to the discussion taking place below maybe let me state my design priorities first. This might help you to focus on that problems that matter most for me.

  1. Cope with bad memory alignment
  2. Get as few operations as possible in terms of performance.

Honestly, if we need the constructors body to get a fast algorithm working, this is fine for me as well. The focus is on raw power.


If you're afraid that passed pointer is not aligned to float boundary (for example, file mapping etc), then you can write something like

template<std::size_t dim>
class Foo {
public:
    Foo(void const * const data)
    {
        float temp[dim];
        memcpy( &temp, data, dim * sizeof( float ) );
        std::copy( temp, temp + dim, vals );
    }
private: 
    double vals[dim];
}

Possibly an overzealous and not-so-portable solution:

template<std::size_t dim>
class Foo {
public:
    Foo(void const * const data)
    {
        if( static_cast<long>( data ) % sizeof( float ) == 0 ) {
            const float *temp = data;
            std::copy( temp, temp + dim, vals );
        } else {
            float temp[dim];
            memcpy( &temp, data, dim * sizeof( float ) );
            std::copy( temp, temp + dim, vals );
        }
    }
private: 
    double vals[dim];
}

Initializing in the initializer list won't make your code faster, it's just a convenience when it's possible.

If you're strongly concerned about performance, I would wrap this if in a macro and only use if on the architectures, which require properly aligned access (x86 is not one, it's just slower on x86).

Edit

Another solution proposed in the comments, thanks to Steve Jessop. It focuses on reducing the temporary variable size.

double *dest = vals;
float tmp;
void const *first = data;
void const *last = data + dim * sizeof(float);
while( first != last ) {
    memcpy( &tmp, first, sizeof(float) );
    first += sizeof(float);
    *dest++ = tmp;
}

A bit of micro-benchmarking/disassebmlying is possibly needed.


Because float is of different size than double, I think the only way is for a manual assignment from one array to the other.

Is it possible to change vals to be an array of float? This will allow you to copy the data array to it using memcpy. Because you don't gain precision in storing the floats in a double array, unless you change vals later to use the great precision of double, you don't gain anything from using doubles.


You cannot initialize an array in initializer list in current C++ standard. You can leverage the fact that you know the size in advance to use std::vector;

template<std::size_t dim>
class Foo {
public:
  Foo(float const * const data) : vals(dim) // fix the vector size
  {
    for(std::size_t i=0; i<dim; i++)
      vals[i] = data[i];  // assignment
  }
private: 
  std::vector<double> vals;
};

I cannot argue that vector<> are as efficient as raw data; but they are well optimized and exception safe.


Why are you hiding the type?

What is wrong with this :

template<std::size_t dim>
class Foo {
public:
    Foo(float const * const data);
private: 
    double vals[dim]
}

template<std::size_t dim>
Foo< dim >::Foo(float const * const data) : vals()
{
  std::copy( data, data+dim, &vals[0] );
}

EDIT

If you switch to std::vector, you can initialize like this:

class Foo {
public:
    Foo(float const * const dataBegin,float const * const dataEnd);
private: 
    std::vector< double > vals;
}

Foo::Foo(float const * const dataBegin,float const * const dataEnd) : vals( dataBegin, dataEnd )
{
}
0

精彩评论

暂无评论...
验证码 换一张
取 消