gpt4 book ai didi

sse - 在 x86(使用 SSE2)和 ARM(使用 vfpv4 NEON)上的尾数为 11 位的 atan2 近似值

转载 作者:行者123 更新时间:2023-12-04 14:31:07 30 4
gpt4 key购买 nike

我正在尝试在尾数中以 11 位精度实现快速 atan2(float)。
atan2 实现将用于图像处理。
所以最好用 SIMD 指令来实现(目标是 x86(带 SSE2)和 ARM(带 vpfv4 NEON))。

现在,我使用切比雪夫多项式近似( https://jp.mathworks.com/help/fixedpoint/examples/calculate-fixed-point-arctangent.html )。

我愿意手动实现矢量化代码。
我将使用 SSE2(或更高版本)和 NEON 包装器库。
我计划或尝试了这些实现选项

  • 矢量化多项式逼近
  • 切比雪夫多项式(现已实现)
  • 标量查找表(+ 线性插值)
  • 矢量化查找表(这可能吗?我不熟悉 NEON,所以我不知道一些指令,例如 NEON 中的 VGATHER)
  • 矢量化 CORDIC 方法(这可能很慢,因为它需要 12 次以上的旋转迭代才能获得 11 位精度)

  • 还有什么好主意?

    最佳答案

    您要检查的第一件事是您的编译器在应用于 atan2f (y,x) 数组时是否能够对 float 进行矢量化。这通常至少需要高优化级别,例如 -O3,并可能指定一种宽松的“快速数学”模式,其中 errno 处理、非正规数和特殊输入(例如无穷大和 NaN)在很大程度上被忽略。使用这种方法,准确性可能远远超过所需,但在性能方面可能很难击败经过仔细调整的库实现。

    接下来要尝试的是编写一个具有足够精度的简单标量实现,并让编译器对其进行矢量化。通常,这意味着避免任何非常简单的分支,这些分支可以通过 if-conversion 转换为无分支代码。此类代码的一个示例是如下所示的 fast_atan2f()。使用作为 icl /O3 /fp:precise /Qvec_report=2 my_atan2f.c 调用的英特尔编译器,这已成功矢量化: my_atan2f.c(67): (col. 9) remark: LOOP WAS VECTORIZED. 通过反汇编对生成的代码进行双重检查表明 fast_atan2f() 已使用 *ps 风格的 SSE 指令进行内联和矢量化。

    如果一切都失败了,您可以手动将 fast_atan2() 的代码转换为特定于平台的 SIMD 内在函数,这应该不难做到。我没有足够的经验来快速完成。

    我在这段代码中使用了一个非常简单的算法,它是一个简单的参数约简以在 [0,1] 中生成一个约简参数,然后是一个极小极大多项式近似,最后一步将结果映射回完整的圆。核心近似是使用 Remez 算法生成的,并使用二阶霍纳方案进行评估。如果可用,可以使用融合乘法加法 (FMA)。出于性能考虑,不处理涉及无穷大、NaN 或 0/0 的特殊情况。

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    /* maximum relative error about 3.6e-5 */
    float fast_atan2f (float y, float x)
    {
    float a, r, s, t, c, q, ax, ay, mx, mn;
    ax = fabsf (x);
    ay = fabsf (y);
    mx = fmaxf (ay, ax);
    mn = fminf (ay, ax);
    a = mn / mx;
    /* Minimax polynomial approximation to atan(a) on [0,1] */
    s = a * a;
    c = s * a;
    q = s * s;
    r = 0.024840285f * q + 0.18681418f;
    t = -0.094097948f * q - 0.33213072f;
    r = r * s + t;
    r = r * c + a;
    /* Map to full circle */
    if (ay > ax) r = 1.57079637f - r;
    if (x < 0) r = 3.14159274f - r;
    if (y < 0) r = -r;
    return r;
    }

    /* Fixes via: Greg Rose, KISS: A Bit Too Simple. http://eprint.iacr.org/2011/007 */
    static unsigned int z=362436069,w=521288629,jsr=362436069,jcong=123456789;
    #define znew (z=36969*(z&0xffff)+(z>>16))
    #define wnew (w=18000*(w&0xffff)+(w>>16))
    #define MWC ((znew<<16)+wnew)
    #define SHR3 (jsr^=(jsr<<13),jsr^=(jsr>>17),jsr^=(jsr<<5)) /* 2^32-1 */
    #define CONG (jcong=69069*jcong+13579) /* 2^32 */
    #define KISS ((MWC^CONG)+SHR3)

    float rand_float(void)
    {
    volatile union {
    float f;
    unsigned int i;
    } cvt;
    do {
    cvt.i = KISS;
    } while (isnan(cvt.f) || isinf (cvt.f) || (fabsf (cvt.f) < powf (2.0f, -126)));
    return cvt.f;
    }

    int main (void)
    {
    const int N = 10000;
    const int M = 100000;
    float ref, relerr, maxrelerr = 0.0f;
    float arga[N], argb[N], res[N];
    int i, j;

    printf ("testing atan2() with %d test vectors\n", N*M);

    for (j = 0; j < M; j++) {
    for (i = 0; i < N; i++) {
    arga[i] = rand_float();
    argb[i] = rand_float();
    }

    // This loop should be vectorized
    for (i = 0; i < N; i++) {
    res[i] = fast_atan2f (argb[i], arga[i]);
    }

    for (i = 0; i < N; i++) {
    ref = (float) atan2 ((double)argb[i], (double)arga[i]);
    relerr = (res[i] - ref) / ref;
    if ((fabsf (relerr) > maxrelerr) &&
    (fabsf (ref) >= powf (2.0f, -126))) { // result not denormal
    maxrelerr = fabsf (relerr);
    }
    }
    };

    printf ("max rel err = % 15.8e\n\n", maxrelerr);

    printf ("atan2(1,0) = % 15.8e\n", fast_atan2f(1,0));
    printf ("atan2(-1,0) = % 15.8e\n", fast_atan2f(-1,0));
    printf ("atan2(0,1) = % 15.8e\n", fast_atan2f(0,1));
    printf ("atan2(0,-1) = % 15.8e\n", fast_atan2f(0,-1));
    return EXIT_SUCCESS;
    }

    上面程序的输出应该类似于以下内容:
    testing atan2() with 1000000000 test vectors
    max rel err = 3.53486939e-005

    atan2(1,0) = 1.57079637e+000
    atan2(-1,0) = -1.57079637e+000
    atan2(0,1) = 0.00000000e+000
    atan2(0,-1) = 3.14159274e+000

    关于sse - 在 x86(使用 SSE2)和 ARM(使用 vfpv4 NEON)上的尾数为 11 位的 atan2 近似值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46210708/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com