【问题标题】:C++: Convert between std::complex and 2x floating point values for use as interfaceC++:在 std::complex 和 2x 浮点值之间转换以用作接口
【发布时间】:2014-08-17 09:49:39
【问题描述】:

布雷夫

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

情况

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

因此描述是;

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

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

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

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

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

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

然后以上述两种形式返回结果:Using std::vector>& (reference to) and float*...

可能的解决方案编号 1

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

不幸的是,我没有编写大部分代码,所以我无法编辑它......解决方案2然后......

可能的解决方案编号 2

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

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

但这不是很好。是否有其他更“时尚”或更直观的方法?

【问题讨论】:

    标签: c++


    【解决方案1】:

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

    专业化complex&lt;float&gt;, complex&lt;double&gt;, 和 complex&lt;long double&gt; 是文字类型 (3.9)。

    [...]

    如果zcv std::complex&lt;T&gt; 类型的左值表达式,则:

    • reinterpret_cast&lt;cv T(&amp;)[2]&gt;(z) 的表达式应该是良构的,
    • reinterpret_cast&lt;cv T(&amp;)[2]&gt;(z)[0] 应指定 z 的实部,并且
    • reinterpret_cast&lt;cv T(&amp;)[2]&gt;(z)[1] 应指定 z 的虚部。

    此外,如果 acv std::complex&lt;T&gt;* 类型的表达式并且 表达式a[i] 为整数表达式i 定义良好, 那么:

    • reinterpret_cast&lt;cv T*&gt;(a)[2*i] 应指定a[i] 的实部,并且
    • reinterpret_cast&lt;cv T*&gt;(a)[2*i + 1] 应指定a[i] 的虚部。

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

    【讨论】:

    • 任何标准布局类都有相同的保证,对吧?
    • @MattMcNabb 没有。这也保证了布局(实部第一,虚部第二),并且除了实部和虚部之外没有其他数据成员。
    • 我的意思是,template&lt;class T&gt; struct domplex { T real; T imag; }; 也会有这些保证(T 是复杂的允许类型之一)
    • @MattMcNabb 的重点是,即使您对类复合体的实现方式一无所知,您也知道它的布局与template&lt;class T&gt; struct domplex { T real; T imag; }; 相同。与向量的保证相同
    • @MattMcNabb:我认为对于template&lt;class T&gt; struct domplex { T real; T imag; };,编译器将被允许在realimag 之间以及结束之后添加填充(尽管我希望没有理智的编译器会这样做所以)。特别是,我认为你不能保证&amp;real + 1 == &amp;imag
    猜你喜欢
    • 2017-10-26
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2011-08-08
    • 2011-01-08
    • 1970-01-01
    相关资源
    最近更新 更多