繁体   English   中英

C中的高效浮点模数一

[英]Efficient floating point modulus one in C

我正在寻找一种 CPU 效率非常高的方法来计算 C 中的浮点模数一(包括负值)。 我将它用于归一化相位减少(包装,即 7.6 -> 0.6、0.2->0.2、-1.1 -> 0.9 等等)。

据我了解, fmod() 以及 floor() 通常效率很低。 我不需要 function 严格,即考虑到 nan 或 inf 因为我负责传递有效值。

我一直在使用

m = x - (float)(int)x +(float)(x<0.f);
// branchless form to add one if x was negative

从基准测试中,它通常比 fmod() 或使用 floor() 代替 int 转换更有效,但我想知道是否存在更有效的方法,可能基于位操作......

我正在使用 gcc 在 64 位英特尔 CPU 上进行编码,但出于我的目的,我使用的是 32 位单精度浮点数。

如果在其他地方也解决了同样的问题,我深表歉意,但从我的搜索中我找不到关于这个特定主题的任何信息。

C++ 中的原型(我不是最新的 C),填充逻辑仍未优化,但如果您的系统上有 AVX512,您可以执行类似的操作来处理 8 个双精度数,或一个循环中的 16 个浮点数。 我在这里发现了很多有用的东西: 内在函数备忘单

我使用了 Visual Studio 2022 中的 MSVC 编译器

#include <type_traits>
#include <vector>
#include <immintrin.h>


void reduce_phases(std::vector<double>& inputs)
{
    static constexpr std::size_t vector_size = 512ul / sizeof(double);
    auto number_to_pad = vector_size - (inputs.size() % vector_size);
    inputs.insert(inputs.end(), number_to_pad, 0.0);

    auto data_ptr = inputs.data();
    
    for (std::size_t n{ 0ul }; n < inputs.size(); n += vector_size, data_ptr += vector_size)
    {
        auto values = _mm512_load_pd(data_ptr);
        auto floors = _mm512_floor_pd(values);
        auto result = _mm512_sub_pd(values, floors);
        _mm512_store_pd(data_ptr, result);
    }

    inputs.erase(inputs.end() - number_to_pad, inputs.end());
}

void reduce_phases(std::vector<float>& inputs)
{
    static constexpr std::size_t vector_size = 512ul / sizeof(float);

    auto number_to_pad = vector_size - (inputs.size() % vector_size);
    inputs.insert(inputs.end(), number_to_pad, 0.0);

    auto data_ptr = inputs.data();

    for (std::size_t n{ 0ul }; n < inputs.size(); n += vector_size, data_ptr += vector_size)
    {
        auto values = _mm512_load_ps(data_ptr);
        auto floors = _mm512_floor_ps(values);
        auto result = _mm512_sub_ps(values, floors);
        _mm512_store_ps(data_ptr, result);
    }

    inputs.erase(inputs.end() - number_to_pad, inputs.end());
}


int main()
{
    std::vector<double> values{ -1.1, -1.9, -1.5, -0.4, 0.0, 0.4, 1.5, 1.9, 2.1 };
    reduce_phases(values);

    std::vector<float> float_values{ -1.1f, -1.9f, -1.5f, -0.4f, 0.0f, 0.4f, 1.5f, 1.9f, 2.1f };
    reduce_phases(float_values);

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM