小编Kum*_*ter的帖子

constexpr函数中的编译时或运行时检测

当constexpr在C++ 11中引入时,我很兴奋,但遗憾的是我对其有用性做出了乐观的假设.我假设我们可以在任何地方使用constexpr来捕获文字编译时常量或文字编译时常量的任何constexpr结果,包括这样的事情:

constexpr float MyMin(constexpr float a, constexpr float b) { return a<b?a:b; }
Run Code Online (Sandbox Code Playgroud)

因为仅将函数的返回类型限定为constexpr并不将其使用限制为编译时,并且还必须在运行时可调用,所以我认为这将是确保MyMin只能与编译时计算的常量一起使用的一种方法,这将确保编译器永远不会允许它在运行时执行,让我可以编写另一个更加运行时友好的MyMin版本,理想情况下使用相同名称使用_mm_min_ss内在函数,确保编译器不会生成运行时分支码.不幸的是,函数参数不能是constexpr,所以似乎无法做到这一点,除非这样的事情是可能的:

constexpr float MyMin(float a, float b)
{
#if __IS_COMPILE_TIME__
    return a<b?a:b;
#else
    return _mm_cvtss_f32(_mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)));
#endif
}
Run Code Online (Sandbox Code Playgroud)

我严重怀疑MSVC++有这样的东西,但是我希望GCC或者clang至少有一些东西可以实现它,不管它看起来有多么不优.

当然,我提供的示例非常简单,但是如果你可以运用你的想象力,在很多情况下你可以随意做一些事情,比如在一个你知道只能在编译时执行的函数中广泛使用分支语句,因为如果它在运行时执行,性能会受到影响.

c++ compile-time constexpr c++14 c++17

20
推荐指数
2
解决办法
3456
查看次数

使用SSE计算绝对值的最快方法

我知道3种方法,但据我所知,通常只使用前2种方法:

  1. 使用andps或屏蔽符号位andnotps.

    • 优点:一个快速指令,如果掩码已经在寄存器中,这使得它非常适合在循环中多次执行此操作.
    • 缺点:掩码可能不在寄存器中或更糟糕,甚至不在缓存中,导致非常长的内存提取.
  2. 将值从零减去否定,然后得到原始的最大值并否定.

    • 优点:固定成本,因为无需取物,就像面具一样.
    • 缺点:如果条件理想,将始终比掩码方法慢,并且我们必须等待subps完成才能使用该maxps指令.
  3. 与选项2类似,将原始值从零减去否定,但随后使用原始值"按位"和"按位" andps.我运行了一个测试,将其与方法2进行比较,除了处理NaNs 之外,它似乎与方法2的行为相同,在这种情况下,结果将NaN与方法2的结果不同.

    • 优点:应该比方法2略快,因为andps通常比速度快maxps.
    • 缺点:当NaN涉及到s 时,这是否会导致任何意外行为?也许不是,因为a NaN仍然是a NaN,即使它是一个不同的值NaN,对吧?

欢迎提出想法和意见.

x86 sse simd vectorization absolute-value

14
推荐指数
1
解决办法
5397
查看次数

c ++析构函数调用删除操作符?

为什么我的MSVC12编译器不喜欢这个?

#include <new>

class thing
{
public:
    thing() {}
    ~thing() {}
    static void operator delete(void* ptr) = delete;
};

int main()
{
    int g;
    void* p = &g;
    thing* t1 = new(p) thing();
    t1->~thing();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误奇怪地在main()的右括号上:

错误2错误C2280:'void thing :: operator delete(void*)':尝试引用已删除的函数

如果我注释掉显式析构函数调用,则错误消失,暗示显式析构函数调用正在尝试调用operator delete(void*).这没有直观意义.正如您可以从这里的代码中看到的那样,我已经管理了自己的内存,并且我不希望任何人在事物上调用delete.

c++ destructor delete-operator

14
推荐指数
1
解决办法
328
查看次数

将 FMA 指令用于 FFT 算法

我有一些 C++ 代码随着时间的推移已经成为一个有点有用的 FFT 库,并且使用 SSE 和 AVX 指令使其运行得非常快。诚然,这一切都仅基于 radix-2 算法,但它仍然成立。我最近最想从头开始是使蝴蝶计算与 FMA 指令一起工作。基本的基数 2 蝴蝶由 4 个乘法和 6 个加法或减法组成。一种简单的方法是用 2 个 FMA 指令替换 2 个加法和减法以及 2 个乘法,从而产生数学上相同的蝴蝶,但显然有更好的方法来做到这一点:

https://books.google.com/books?id=2HG0DwAAQBAJ&pg=PA56&lpg=PA56&dq=radix+2+fft+fma&source=bl&ots=R5XDWyYBVv&sig=ACfU3U0S2n1hcgiP63LTKMxI5Oc85eEZaQ&hl=en&sa=X&ved=2ahUKEwiz_I3PsrToAhVoHzQIHYmVDGIQ6AEwDXoECAoQAQ#v=onepage&q=radix%202%20fft% 20fma&f=假

ci1 = ci1 / cr1
u0 = zinr(0)
v0 = zini(0)
r = zinr(1)
s = sini(1)
u1 = r - s * ci1
v1 = r * ci1 + s
zoutr(0) = u0 + u1 * cr1
zouti(0) = v0 + v1 * cr1
zoutr(1) = u0 - u1 * …
Run Code Online (Sandbox Code Playgroud)

c++ signal-processing fft fma

5
推荐指数
1
解决办法
226
查看次数

从SSE切换到AVX的处罚?

我知道从AVX指令切换到SSE指令的现有惩罚,而没有先将所有ymm寄存器的上半部分归零,但在我的机器上的特殊情况下(i7-3939K 3.2GHz),似乎有一个非常反之亦然(SSE到AVX),即使我在AVX代码部分之前和之后明确使用_mm256_zeroupper.

我编写了用于在32位浮点数和32位定点整数之间进行转换的函数,在2个32768元素宽的缓冲区上.我将一个SSE2内在版本直接移植到AVX,在SSE的4上同时执行8个元素,期望看到显着的性能提升,但不幸的是,相反的情况发生了.

所以,我有2个功能:

void ConvertPcm32FloatToPcm32Fixed(int32* outBuffer, const float* inBuffer, uint sampleCount, bool bUseAvx)
{
    const float fScale = (float)(1U<<31);

    if (bUseAvx)
    {
        _mm256_zeroupper();
        const __m256 vScale = _mm256_set1_ps(fScale);
        const __m256 vVolMax = _mm256_set1_ps(fScale-1);
        const __m256 vVolMin = _mm256_set1_ps(-fScale);

        for (uint i = 0; i < sampleCount; i+=8)
        {
            const __m256 vIn0 = _mm256_load_ps(inBuffer+i); // Aligned load
            const __m256 vVal0 = _mm256_mul_ps(vIn0, vScale);
            const __m256 vClamped0 = _mm256_min_ps( _mm256_max_ps(vVal0, vVolMin), vVolMax );
            const __m256i vFinal0 = _mm256_cvtps_epi32(vClamped0);
            _mm256_store_si256((__m256i*)(outBuffer+i), vFinal0); // …
Run Code Online (Sandbox Code Playgroud)

c++ sse avx sse2

4
推荐指数
1
解决办法
1910
查看次数