当前位置: 首页 > 知识库问答 >
问题:

等间距角正弦、余弦的快速准确迭代生成

桓高澹
2023-03-14

共有1个答案

阎丰
2023-03-14

正弦半角公式的应用可以解决问题中提到的两个影响精度的问题:

sin(incr/2)=√((1-cos(incr))/2)¥
sinÁ(incr/2)=(1-cos(incr))/2
2·sinÁ(incr/2)=1-cos(incr)
1-2·sinÁ(incr/2)=cos(incr)

将其代入到原始公式中会得到这个中间表示:

sin(碱基+incr)=fma(-2·sinÁ(incr/2),sin(碱基),fma(sin(incr),cos(碱基),sin(碱基)))
cos(碱基+incr)=fma(-2·sinÁ(incr/2),cos(碱基),fma(-sin(incr),sin(碱基),cos(碱基)))

另一种选择是将单个FMA应用于改进的公式,尽管目前还不清楚两个乘法中的哪一个应该映射到FMA内部的非舍入乘法:

sin(碱基+incr)=sin(碱基)+fma(sin(incr),cos(碱基),-2·sin(incr/2)·sin(碱基))
cos(碱基+incr)=cos(碱基)-fma(sin(incr),sin(碱基),2·sin(incr/2)·cos(碱基))

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

#define NAIVE    (1)
#define ROBUST   (2)
#define FAST     (3)
#define ACCURATE (4)
#define MODE (ACCURATE)

// 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)

int main (void)
{
    double sumerrsqS, sumerrsqC, rmsS, rmsC, maxrmsS = 0, maxrmsC = 0;
    double refS, refC, errS, errC;
    float base, incr, s0, c0, s1, c1, tt;
    int count, i;

    const int N = 100;  // # rotation steps per test case
    count = 2000000;    // # test cases (a pair of base and increment values)

#if MODE == NAIVE
    printf ("testing: NAIVE (without FMA)\n");
#elif MODE == FAST
    printf ("testing: FAST (without FMA)\n");
#elif MODE == ACCURATE
    printf ("testing: ACCURATE (with FMA)\n");
#elif MODE == ROBUST
    printf ("testing: ROBUST (with FMA)\n");
#else
#error unsupported MODE
#endif // MODE

    do {
        /* generate test case */
        base = (float)(KISS * 1.21e-10);      // starting angle, < 30 degrees
        incr = (float)(KISS * 2.43e-10 / N);  // increment, < 60/n degrees

        /* set up rotation parameters */
        s1 = sinf (incr);
#if MODE == NAIVE
        c1 = cosf (incr);
#else
        tt = sinf (incr * 0.5f);
        c1 = 2.0f * tt * tt;
#endif // MODE
        sumerrsqS = 0;
        sumerrsqC = 0;

        s0 = sinf (base); // initial sine
        c0 = cosf (base); // initial cosine

        /* run test case through N rotation steps */
        i = 0;
        do {         

            tt = s0; // old sine
#if MODE == NAIVE
            /* least accurate, 6 FP ops */
            s0 = c1 * tt + s1 * c0; // new sine
            c0 = c1 * c0 - s1 * tt; // new cosine
#elif MODE == ROBUST
            /* very accurate, 8 FP ops */
            s0 = ( s1 * c0 - c1 * tt) + tt; // new sine
            c0 = (-s1 * tt - c1 * c0) + c0; // new cosine
#elif MODE == FAST
            /* accurate and fast, 4 FP ops */
            s0 = fmaf (-c1, tt, fmaf ( s1, c0, tt)); // new sine
            c0 = fmaf (-c1, c0, fmaf (-s1, tt, c0)); // new cosine
#elif MODE == ACCURATE
            /* most accurate, 6 FP ops */
            s0 = tt + fmaf (s1, c0, -c1 * tt); // new sine
            c0 = c0 - fmaf (s1, tt,  c1 * c0); // new cosine
#endif // MODE
            i++;

            refS = sin (fma ((double)i, (double)incr, (double)base));
            refC = cos (fma ((double)i, (double)incr, (double)base));
            errS = ((double)s0 - refS) / refS;
            errC = ((double)c0 - refC) / refC;
            sumerrsqS = fma (errS, errS, sumerrsqS);
            sumerrsqC = fma (errC, errC, sumerrsqC);
        } while (i < N);

        rmsS = sqrt (sumerrsqS / N);
        rmsC = sqrt (sumerrsqC / N);
        if (rmsS > maxrmsS) maxrmsS = rmsS;
        if (rmsC > maxrmsC) maxrmsC = rmsC;

    } while (--count);

    printf ("max rms error sin = % 16.9e\n", maxrmsS);
    printf ("max rms error cos = % 16.9e\n", maxrmsC);

    return EXIT_SUCCESS;
}
testing: NAIVE (without FMA)
max rms error sin =  4.837386842e-006
max rms error cos =  6.884047862e-006

testing: ROBUST (without FMA)
max rms error sin =  3.330292645e-006
max rms error cos =  4.297631502e-006

testing: FAST (with FMA)
max rms error sin =  3.532624939e-006
max rms error cos =  4.763623188e-006

testing: ACCURATE (with FMA)
max rms error sin =  3.330292645e-006
max rms error cos =  4.104813533e-006
 类似资料:
  • /编辑:很抱歉缺少一个问题。我需要知道如何使用正弦和余弦来画一个正方形或矩形,旋转中心在正方形或矩形的左上角。用角度的sin和cos得到坐标(x1,y1),然后用角度的sin和cos函数加上90度得到坐标(x2,y2)。使用计数器变量从左到右,从上到下绘制线条,随角度变化。

  • 问题内容: 我计算了两个文档的tf / idf值。以下是tf / idf值: 这些文件就像: 如何使用这些值来计算余弦相似度? 我知道我应该计算点积,然后找到距离并除以点积。如何使用我的值来计算? 还有一个问题: 两个文档的字数相同是否重要? 问题答案: a * b是点积 一些细节: 是。在某种程度上,a和b必须具有相同的长度。但是a和b通常具有稀疏表示,您只需要存储非零条目,就可以更快地计算范数

  • 我试图生成一组点,当绘制成一个图表示1个周期的正弦波。要求是: 1个周期的正弦波 下限=29491 上限=36043 点数=100 振幅=3276 零偏移量=32767 代码: 我正在生成并存储一个文件中的点。当这些点被绘制出来时,我得到了下面的图。 但我只需要一个循环。我怎么能这么做?

  • 用C/C++编写了一个三维正弦波发生器 代码:

  • 我如何建立一个方程来产生扫频正弦波。我是信号处理新手,在网上找不到太多关于生成扫描正弦波的话题。请告诉我一些我可以用来生成方程式并在代码中使用的源代码。非常感谢。

  • 我在许多正弦/余弦的应用中都看到了一种所谓的扩展模精度算法。但这是为了什么?例如,在cephes实验中,在缩小到[0,pi/4]范围后,他们正在进行这种模块化精度算法来提高精度。 守则如下: 其中DP1、DP2和DP3是一些硬编码系数。如何从数学上求出这些系数?我已经理解了“模块扩展算术”对于big num的目的,但是这里它的确切目的是什么呢?