簡體   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