在初始化列表中从 float* 设置 double[]

发布于 2024-11-26 01:44:10 字数 524 浏览 5 评论 0原文

我有一个大致如下所示的类:

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

对于构造函数,我知道 void* data 指向一个 float 值数组(维度为 dim)。现在我想在该构造函数的初始化列表中初始化 vals 数组(最好)。

更糟糕的是,所指向的浮点数不一定必须正确地进行内存对齐。

我怎样才能有效地做到这一点?


编辑 1

关于下面进行的讨论,也许让我先说明我的设计优先事项。这可能会帮助您专注于对我来说最重要的问题。

  1. 应对不良的内存对齐
  2. 在性能方面尽可能少地执行操作。

老实说,如果我们需要构造函数主体来使算法快速运行,这对我来说也很好。重点是原始功率。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

温柔戏命师 2024-12-03 01:44:10

如果您担心传递的指针未与 float 边界对齐(例如,文件映射等),那么您可以编写类似的内容

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];
}

可能是一个过于热心且不太可移植的解决方案:

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];
}

在初始化列表不会使您的代码更快,它只是在可能的情况下提供便利。

如果您非常关心性能,我会将这个 if 包装在一个宏中,并且仅在需要正确对齐访问的体系结构上使用 if(x86 不是一个,只是在 x86 上速度较慢)。

编辑

评论中提出的另一个解决方案,感谢
史蒂夫·杰索普。它的重点是减少临时变量的大小。

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;
}

可能需要一些微基准测试/反汇编。

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.

述情 2024-12-03 01:44:10

由于 float 的大小与 double 不同,我认为唯一的方法是从一个数组到另一个数组的手动分配。

是否可以将 vals 更改为 float 数组?这将允许您使用 memcpydata 数组复制到其中。因为将 float 存储在 double 数组中时无法获得精度,除非稍后更改 vals 以使用 float 的高精度code>double,你不会从使用 double 中获得任何东西。

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.

寄风 2024-12-03 01:44:10

在当前 C++ 标准中,您无法初始化初始值设定项列表中的数组。您可以利用提前知道大小的事实来使用 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;
};

我不能说向量与原始数据一样高效;但它们经过了很好的优化并且异常安全。

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.

谜兔 2024-12-03 01:44:10

为什么要隐藏类型?

这是什么问题:

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] );
}

编辑

如果你切换到std::vector,你可以像这样初始化:

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 )
{
}

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 )
{
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文