C++:在 std::complex 和 2x 浮点值之间转换以用作接口(interface)

标签 c++

简介

我希望能够以最小的数据复制开销在 std::complex 和 float 之间进行转换。 (如果可能的话,完全没有。)

情况

我有一个包含数据样本的类。在类的一侧,有一个程序以 std::complex 的形式读写数据。数据要么全是实值,要么全是虚数,因此输入是 (float*)。在类内部有一个函数进行处理,例如傅立叶变换处理,它的参数是float*。 (指向 float 的指针。)类内的数据存储在 std::vector 中。

因此描述是;

std::vector<std::complex<float>> ;

做出这种选择的原因是输出并不总是实数或虚数。使用 vector.at(index).real() 或 vector.at(index).imag() 访问数据将是有利的,因为这使得编写其他函数(例如计算平均功率的函数)更加容易. (另一种方法是使用索引来取消引用指针。通常,我不会对这种方法有任何问题,但是许多其他 SO 程序员会告诉您这是一种糟糕的方法,因为您必须能够乘以 2 并添加向上...在这种情况下,要确保算法正确变得更加困难,因为数据存储方式发生了变化[1],因此我同意 SO 共识的原因例。)

[1]:输入数据是一个(float*)到所有实数值。 2 个输入值 block 交织成一个两倍大小的数组:real0 = data0[0],imag0 = data1[0],real1 = data0[1],imag1 = data1[1],...等...

然后存储为:{ complex(real0, imag0) , complex(real1, imag1) , ... etc ... }

但随后使用 FFT 进行处理,该 FFT 采用 float*,并使用索引而不是 complex.real() 和 complex.imag()。

然后另一组函数使用 complex.real() 和 complex.imag() 而不仅仅是索引来计算值。

然后结果以上述两种形式返回:使用 std::vector>& (引用)和 float*...

可能的解决方案编号 1

显然,这种改变数据存储方式的方法是愚蠢的。它应该是一种或另一种方式,而不是多种不同的方式。

不幸的是,这段代码的大部分不是我写的,所以我无法对其进行编辑...然后是解决方案 2...

可能的解决方案编号 2

可以返回指向 vector 类中数据的指针。为此,我假设:

std::complex 类按该顺序存储实值和虚值

如果这不是真的,以下将不起作用:

// Function inside my_class which returns access to real components
float* getReal(int& stride, int& length)
{
    stride = 2;
    return &my_vector.at(0); // Think this is the same as my_vector.data()?
}

// This is then used in the following way to set all real values to 0.0
void Reset()
{
    int stride, length;
    float* data_p = my_class.getReal(stride, length);
    float* data_p_last_value = data_p + length - 1;

    for(; data_p <= data_p_last_value; ++ data_p)
    {
        (*data_p) = 0.0;
    }
}

但这有点不太好。是否有更“圆滑”或更直观的替代方法?

最佳答案

std::complex是一个非常特殊的类,指定用于与其他语言(包括 C)中的复数类型的互操作性。该标准保证 (§26.4 [complex.numbers]/p2, 4):

The specializations complex<float>, complex<double>, and complex<long double> are literal types (3.9).

[...]

If z is an lvalue expression of type cv std::complex<T> then:

  • the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,
  • reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and
  • reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.

Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i, then:

  • reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
  • reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].

因此,您建议的解决方案 2 中的方法是安全的模数错误(例如,您在 length 中使用 Reset() 未初始化,并且您的算法似乎将所有内容归零,而不仅仅是实部)。

关于C++:在 std::complex 和 2x 浮点值之间转换以用作接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25348099/

相关文章:

c++ - ReadDebuggeeMemoryEx 读取调试对象失败

c++ - 使用 LoadLibrary 后未调用 DllMain

c++ - 如何为 QtWebKit 安装插件

c++ - 通过引用符号传递

c++ - 在 gdb 中设置一个文件范围的断点

c++ - 如何使表格的列可编辑?

c++ - 如何转发声明用作成员变量的结构

c++ - Visual Studio中函数调用和第一行函数之间的代码损坏问题

c++ - 将 LPCWSTR 字符串打印到文件

c++ - C++中j+=(i=j)是什么意思