【问题标题】:Implementation of sine function in C not workingC中正弦函数的实现不起作用
【发布时间】:2017-12-28 21:33:49
【问题描述】:

我尝试在 C 中实现正弦函数,但得到了奇怪的结果。以下是我用来计算正弦的三个函数:

#define PI 3.14159265358979323846
#define DEPTH 16

double sine(long double);
long double pow(long double, unsigned int);
unsigned int fact(unsigned int);

double sine(long double x) {
    long double i_x = x *= PI/180;
    int n = 3, d = 0, sign = -1;

    // fails past 67 degrees
    for (; d < DEPTH; n += 2, d++, sign *= -1) {
        x += pow(i_x, n) / fact(n) * sign;
    }

    return x;
}

long double pow(long double base, unsigned int exp) {
    double answer = 1;
    while (exp) {
        answer *= base;
        exp--;
    }
    return answer;
}

unsigned int fact(unsigned int n) {
    unsigned int answer = 1;
    while (n > 1) {
        answer *= n--;
    }
    return answer;
}

为了测试它,我一直在针对内置的正弦函数对其进行测试,如下所示:

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

main() {
    for (int i = 0; i <= 180; i++) {
        printf("sin(%i) = %lf, %lf\n", i, sine(i), sin(i*3.14159265358979323846/180));
    }

    exit(EXIT_SUCCESS);
}

向上到 67 度,它的计算与内置函数相同。但是,随着它增加到超过 67,它通常会越来越远离实际值。

这是一个示例输出:

>> sin(100) = 0.987711, 0.984808
>> sin(101) = 0.986885, 0.981627
>> sin(102) = 0.987056, 0.978148
>> sin(103) = 0.988830, 0.974370
>> sin(104) = 0.993060, 0.970296
>> sin(105) = 1.000948, 0.965926
>> sin(106) = 1.014169, 0.961262
>> sin(107) = 1.035052, 0.956305
>> sin(108) = 1.066807, 0.951057
>> sin(109) = 1.113846, 0.945519
>> sin(110) = 1.182194, 0.939693
>> sin(111) = 1.280047, 0.933580
>> sin(112) = 1.418502, 0.927184
>> sin(113) = 1.612527, 0.920505
>> sin(114) = 1.882224, 0.913545
>> sin(115) = 2.254492, 0.906308
>> sin(116) = 2.765192, 0.898794
>> sin(117) = 3.461969, 0.891007
              ...
>> sin(180) = 8431648.192239, 0.000000

有人知道为什么会这样吗?我在 Windows 7 上使用 Visual Studio 2017,如果它提供了任何有用的信息。

【问题讨论】:

  • 为什么要重新定义标准的pow函数?
  • 阶乘 12 (12!) 是可以用 32 位整数表示的最大阶乘; 20!是可以用 64 位整数表示的最大值。您的fact() 函数是一个可能的麻烦来源。
  • 标准定义了pow(),并在&lt;math.h&gt;中声明。为了安全起见,请使用不同的名称。
  • 请注意,使用 long double 不会为您提供额外的精度,因为 Microsoft 的 C 运行时库将 long double 映射到 double,因此只有 IEEE 754 标准中概述的 64 位双精度浮点。
  • 2 个主要问题:factional overflow 和缺乏范围缩减。对于更大的 x 值,除非使用越来越多的术语,否则泰勒的级数会失败。使用remquo(x,45.0, &amp;quo) 带入+/- 45 度范围,然后应用三角恒等式和系列解决方案。 remquo() example

标签: c trigonometry


【解决方案1】:

您的多项式级数评估方式是numerically unstable。试试horner's method,它比幂计算更稳定。

【讨论】:

    【解决方案2】:

    每次for loop 进行时,n 都会增加2,因此对于DEPTH = 16,在循环结束附近,您必须计算与30 一样大的数字的阶乘并且您正在使用@ 987654327@ 只能存储与 2^32 = 4294967296 ~= 12! 一样大的值,这会导致您的阶乘函数溢出,进而给您错误的阶乘。

    即使你使用了long double 并且我已经在我的 cmets 中声明 MSCRT 中的 long double 映射到 double (Reference) 你仍然会在更大的角度看到一些异常,因为尽管 @ 987654332@ 可以存储与1.8E+308 一样大的值,但它在2^53 = 9007199254740992 ~= 18! 处失去了粒度(即2^53 + 1 存储为double 等于2^53)。因此,一旦您在角度上增加,这种行为的影响会变得越来越大,以至于在您与 printf() 一起使用的 6 位小数精度中很明显。

    尽管您走在正确的轨道上,但您应该使用像 GMPlibcrypto 这样的 bignum 库。他们可以在不损失精度的情况下执行这些计算。

    顺便说一句,由于您是在 Windows 7 上开发的,这意味着您使用的是 x86 或 x86-64。在这些平台上,x87 能够以 80 位执行扩展精度(根据 754 标准)操作,但我不知道编译器内在函数可以在不求助于汇编代码的情况下为您提供该功能。

    我还想请您注意范围缩小技术。尽管我仍然建议使用 bignum 库,但如果您在 090 度之间(045,如果我更严格的话),您可以计算所有其他角度的 sine()只需简单的三角恒等式

    更新:

    实际上,我会纠正自己在阶乘计算中使用 doubles 的问题。在编写了一个简单的程序后,我验证了当我使用double 存储阶乘时,即使我高于18,它们也是正确的。经过一番思考,我意识到在 factorials 的情况下,double 粒度的情况有点复杂。我举个例子说明一下:

    19! = 19 * 18 * ... * 2 * 1
    

    在这个数字中,18, 16, 14, ... , 2 都是 2 的倍数,并且因为乘以 2 相当于在二进制表示中向左移动,所以 19! 中的所有低位都已经是 0,因此当double整数 大于2^53 时,这些阶乘不受影响。您可以通过计算2 的数量(即16)来计算19! 的二进制表示中最低有效零的数量。 (对于20!,是18

    我要去1.8e+308 并检查所有阶乘是否不受影响。我会告诉你结果。

    更新 2:

    如果我们使用doubles 来保存阶乘,它们会受到从23! 开始的四舍五入的影响。它可以很容易地显示出来,因为2^74 &lt; 23! &lt; 2^75这意味着至少需要75位的精度来表示它,但是由于23!19的最低有效位为0,所以它需要@987654368 @ 大于double 提供的53 位。

    对于22!,为51 bits(你可以自己计算)。

    【讨论】:

    • 很好的答案!如果您还没有被告知,欢迎来到 Stack Overflow,继续努力。
    • 谢谢@PatrickRoberts,你真好。我会尽力的。
    【解决方案3】:

    你的问题在这里:

    for (; d < DEPTH; n += 2, d++, sign *= -1) {
        x += pow(i_x, n) / fact(n) * sign;
    }
    

    您错误地使用了d &lt; DEPTH,而它应该是n &lt; DEPTHd 与您在循环中的计算无关。以下应该可以工作——尽管我还没有编译测试。

    for (; n < DEPTH; n += 2, sign *= -1) {
        x += pow(i_x, n) / fact(n) * sign;
    }
    

    注意:DEPTH12(例如,泰勒级数扩展,带有项 1, 3, 5, ... 11)足以解决 3e-10 错误——60-degrees 处的十亿分之三。 (虽然误差随着0-360 之间的角度增加而增加,但20DEPTH 将在整个范围内保持误差小于1.0e-8。)

    启用编译器警告会在sine 中捕获未使用的d

    这里是一个更改的代码示例(注意:Gnu 为 PI 提供了一个常量 M_PI):

    #include <stdio.h>
    #include <stdint.h>
    #include <math.h>
    
    #define DEPTH 16
    
    /* n factorial */
    uint64_t nfact (int n)
    {
        if (n <= 0) return 1;
    
        uint64_t s = n;
    
        while (--n)
            s *= n;
    
        return s;
    }
    
    /* y ^ x */
    double powerd (const double y, const int x)
    {
        if (!x) return 1;
    
        double r = y;
    
        for (int i = 1; i < x; i++)
            r *= y;
    
        return r;
    }
    
    double sine (double deg)
    {
        double rad = deg * M_PI / 180.0,
            x = rad;
        int sign = -1;
    
        for (int n = 3; n < DEPTH; n += 2, sign *= -1)
            x += sign * powerd (rad, n) / nfact (n);
    
        return x;
    }
    
    int main (void) {
    
        printf (" deg       sin            sine\n\n");
        for (int i = 0; i < 180; i++)
            printf ("%3d    %11.8f    %11.8f\n", i, sin (i * M_PI / 180.0), sine (i));
    
        return 0;
    }
    

    使用/输出示例

    $ ./bin/sine
     deg       sin            sine
    
      0     0.00000000     0.00000000
      1     0.01745241     0.01745241
      2     0.03489950     0.03489950
      3     0.05233596     0.05233596
      4     0.06975647     0.06975647
      5     0.08715574     0.08715574
      6     0.10452846     0.10452846
      7     0.12186934     0.12186934
      8     0.13917310     0.13917310
      9     0.15643447     0.15643447
     10     0.17364818     0.17364818
     11     0.19080900     0.19080900
     12     0.20791169     0.20791169
     13     0.22495105     0.22495105
     14     0.24192190     0.24192190
     15     0.25881905     0.25881905
     16     0.27563736     0.27563736
     17     0.29237170     0.29237170
     18     0.30901699     0.30901699
     19     0.32556815     0.32556815
     20     0.34202014     0.34202014
     21     0.35836795     0.35836795
     22     0.37460659     0.37460659
     23     0.39073113     0.39073113
     24     0.40673664     0.40673664
     25     0.42261826     0.42261826
     26     0.43837115     0.43837115
     27     0.45399050     0.45399050
     28     0.46947156     0.46947156
     29     0.48480962     0.48480962
     30     0.50000000     0.50000000
     31     0.51503807     0.51503807
     32     0.52991926     0.52991926
     33     0.54463904     0.54463904
     34     0.55919290     0.55919290
     35     0.57357644     0.57357644
     36     0.58778525     0.58778525
     37     0.60181502     0.60181502
     38     0.61566148     0.61566148
     39     0.62932039     0.62932039
     40     0.64278761     0.64278761
     41     0.65605903     0.65605903
     42     0.66913061     0.66913061
     43     0.68199836     0.68199836
     44     0.69465837     0.69465837
     45     0.70710678     0.70710678
     46     0.71933980     0.71933980
     47     0.73135370     0.73135370
     48     0.74314483     0.74314483
     49     0.75470958     0.75470958
     50     0.76604444     0.76604444
     51     0.77714596     0.77714596
     52     0.78801075     0.78801075
     53     0.79863551     0.79863551
     54     0.80901699     0.80901699
     55     0.81915204     0.81915204
     56     0.82903757     0.82903757
     57     0.83867057     0.83867057
     58     0.84804810     0.84804810
     59     0.85716730     0.85716730
     60     0.86602540     0.86602540
     61     0.87461971     0.87461971
     62     0.88294759     0.88294759
     63     0.89100652     0.89100652
     64     0.89879405     0.89879405
     65     0.90630779     0.90630779
     66     0.91354546     0.91354546
     67     0.92050485     0.92050485
     68     0.92718385     0.92718385
     69     0.93358043     0.93358043
     70     0.93969262     0.93969262
     71     0.94551858     0.94551858
     72     0.95105652     0.95105652
     73     0.95630476     0.95630476
     74     0.96126170     0.96126170
     75     0.96592583     0.96592583
     76     0.97029573     0.97029573
     77     0.97437006     0.97437006
     78     0.97814760     0.97814760
     79     0.98162718     0.98162718
     80     0.98480775     0.98480775
     81     0.98768834     0.98768834
     82     0.99026807     0.99026807
     83     0.99254615     0.99254615
     84     0.99452190     0.99452190
     85     0.99619470     0.99619470
     86     0.99756405     0.99756405
     87     0.99862953     0.99862953
     88     0.99939083     0.99939083
     89     0.99984770     0.99984770
     90     1.00000000     1.00000000
     91     0.99984770     0.99984770
     92     0.99939083     0.99939083
     93     0.99862953     0.99862953
     94     0.99756405     0.99756405
     95     0.99619470     0.99619470
     96     0.99452190     0.99452190
     97     0.99254615     0.99254615
     98     0.99026807     0.99026807
     99     0.98768834     0.98768834
    100     0.98480775     0.98480775
    101     0.98162718     0.98162718
    102     0.97814760     0.97814760
    103     0.97437006     0.97437006
    104     0.97029573     0.97029573
    105     0.96592583     0.96592583
    106     0.96126170     0.96126170
    107     0.95630476     0.95630476
    108     0.95105652     0.95105652
    109     0.94551858     0.94551858
    110     0.93969262     0.93969262
    111     0.93358043     0.93358043
    112     0.92718385     0.92718385
    113     0.92050485     0.92050485
    114     0.91354546     0.91354546
    115     0.90630779     0.90630779
    116     0.89879405     0.89879405
    117     0.89100652     0.89100652
    118     0.88294759     0.88294759
    119     0.87461971     0.87461971
    120     0.86602540     0.86602540
    121     0.85716730     0.85716730
    122     0.84804810     0.84804810
    123     0.83867057     0.83867057
    124     0.82903757     0.82903757
    125     0.81915204     0.81915204
    126     0.80901699     0.80901699
    127     0.79863551     0.79863551
    128     0.78801075     0.78801075
    129     0.77714596     0.77714596
    130     0.76604444     0.76604444
    131     0.75470958     0.75470958
    132     0.74314483     0.74314482
    133     0.73135370     0.73135370
    134     0.71933980     0.71933980
    135     0.70710678     0.70710678
    136     0.69465837     0.69465836
    137     0.68199836     0.68199835
    138     0.66913061     0.66913060
    139     0.65605903     0.65605902
    140     0.64278761     0.64278760
    141     0.62932039     0.62932038
    142     0.61566148     0.61566146
    143     0.60181502     0.60181501
    144     0.58778525     0.58778523
    145     0.57357644     0.57357642
    146     0.55919290     0.55919288
    147     0.54463904     0.54463901
    148     0.52991926     0.52991924
    149     0.51503807     0.51503804
    150     0.50000000     0.49999996
    151     0.48480962     0.48480958
    152     0.46947156     0.46947152
    153     0.45399050     0.45399045
    154     0.43837115     0.43837109
    155     0.42261826     0.42261820
    156     0.40673664     0.40673657
    157     0.39073113     0.39073105
    158     0.37460659     0.37460651
    159     0.35836795     0.35836786
    160     0.34202014     0.34202004
    161     0.32556815     0.32556804
    162     0.30901699     0.30901686
    163     0.29237170     0.29237156
    164     0.27563736     0.27563720
    165     0.25881905     0.25881887
    166     0.24192190     0.24192170
    167     0.22495105     0.22495084
    168     0.20791169     0.20791145
    169     0.19080900     0.19080873
    170     0.17364818     0.17364788
    171     0.15643447     0.15643414
    172     0.13917310     0.13917274
    173     0.12186934     0.12186895
    174     0.10452846     0.10452803
    175     0.08715574     0.08715526
    176     0.06975647     0.06975595
    177     0.05233596     0.05233537
    178     0.03489950     0.03489886
    179     0.01745241     0.01745170
    

    基于深度的错误检查

    针对有关计算错误的评论,您通过改变DEPTH 并设置最大错误@ 987654343@ 对0-360(或0-2PI)的范围使用类似于以下的内容,

    #define DEPTH 20
    #define EMAX 1.0e-8
    ...
    /* sine as above */
    ...
    /* cos with taylor series expansion to n = DEPTH */
    long double cose (const long double deg)
    {
        long double rad = deg * M_PI / 180.0,
            x = 1.0;
        int sign = -1;
    
        for (int n = 2; n < DEPTH; n += 2, sign *= -1)
            x += sign * powerd (rad, n) / nfact (n);
    
        return x;
    }
    
    int main (void) {
    
        for (int i = 0; i < 180; i++) {
            long double sinlibc = sin (i * M_PI / 180.0),
                coslibc = cos (i * M_PI / 180.0),
                sints = sine (i),
                costs = cose (i),
                serr = fabs (sinlibc - sints),
                cerr = fabs (coslibc - costs);
    
            if (serr > EMAX)
                fprintf (stderr, "sine error exceeds limit of %e\n"
                "%3d    %11.8Lf    %11.8Lf    %Le\n",
                EMAX, i, sinlibc, sints, serr);
    
            if (cerr > EMAX)
                fprintf (stderr, "cose error exceeds limit of %e\n"
                "%3d    %11.8Lf    %11.8Lf    %Le\n",
                EMAX, i, coslibc, costs, cerr);
        }
    
        return 0;
    }
    

    如果您检查,您会发现对于小于DEPTH 20(每个扩展10 个项)的任何内容,对于更高的角度,误差将超过1.0e-8。令人惊讶的是,对于 DEPTH 的值低至 12(6 项),第一象限的扩展非常准确。


    Addemdum - 使用0-90 和象限提高泰勒级数精度

    在正常的泰勒级数展开中,误差随着角度的增加而增加。而且...因为有些人不能不修补,我想进一步比较libc sin/cos 和泰勒级数之间的准确性,如果计算限制在0-90 度并且处理90-360 的剩余时间段按象限 (2, 3 &amp; 4) 镜像来自 0-90 的结果。它的工作原理——非常棒。

    例如,仅处理角度 0-90 以及将 90 - 180180 - 270270 - 360 之间的角度加上初始 angle % 360 产生的结果与 libc 数学库函数相当。 libc 和810 术语泰勒级数展开之间的最大误差分别是:

    来自 libc 的最大错误 sin/cos

    TSLIM 16

    sine_ts max err at :  90.00 deg  -- 6.023182e-12
    cose_ts max err at : 270.00 deg  -- 6.513370e-11
    

    TSLIM 20

    sine_ts max err at : 357.00 deg  -- 5.342948e-16
    cose_ts max err at : 270.00 deg  -- 3.557149e-15
    

    (大量的角度完全没有区别)

    泰勒级数的sinecose 的调整版本如下:

    double sine (const double deg)
    {
        double fp = deg - (int64_t)deg, /* save fractional part of deg */
            qdeg = (int64_t)deg % 360,  /* get equivalent 0-359 deg angle */
            rad, sine_deg;              /* radians, sine_deg */
        int pos_quad = 1,               /* positive quadrant flag 1,2  */
            sign = -1;                  /* taylor series term sign */
    
        qdeg += fp;                     /* add fractional part back to angle */
    
        /* get equivalent 0-90 degree angle, set pos_quad flag */
        if (90 < qdeg && qdeg <= 180)           /* in 2nd quadrant */
            qdeg = 180 - qdeg;
        else if (180 < qdeg && qdeg <= 270) {   /* in 3rd quadrant */
            qdeg = qdeg - 180;
            pos_quad = 0;
        }
        else if (270 < qdeg && qdeg <= 360) {   /* in 4th quadrant */
            qdeg = 360 - qdeg;
            pos_quad = 0;
        }
    
        rad = qdeg * M_PI / 180.0;      /* convert to radians */
        sine_deg = rad;                 /* save copy for computation */
    
        /* compute Taylor-Series expansion for sine for TSLIM / 2 terms */
        for (int n = 3; n < TSLIM; n += 2, sign *= -1) {
            double p = rad;
            uint64_t f = n;
    
            for (int i = 1; i < n; i++)     /* pow */
                p *= rad;
    
            for (int i = 1; i < n; i++)     /* nfact */
                f *= i;
    
            sine_deg += sign * p / f;       /* Taylor-series term */
        }
    
        return pos_quad ? sine_deg : -sine_deg;
    }
    

    对于cos

    double cose (const double deg)
    {
        double fp = deg - (int64_t)deg, /* save fractional part of deg */
            qdeg = (int64_t)deg % 360,  /* get equivalent 0-359 deg angle */
            rad, cose_deg = 1.0;        /* radians, cose_deg */
        int pos_quad = 1,               /* positive quadrant flag 1,4  */
            sign = -1;                  /* taylor series term sign */
    
        qdeg += fp;                     /* add fractional part back to angle */
    
        /* get equivalent 0-90 degree angle, set pos_quad flag */
        if (90 < qdeg && qdeg <= 180) {         /* in 2nd quadrant */
            qdeg = 180 - qdeg;
            pos_quad = 0;
        }
        else if (180 < qdeg && qdeg <= 270) {   /* in 3rd quadrant */
            qdeg = qdeg - 180;
            pos_quad = 0;
        }
        else if (270 < qdeg && qdeg <= 360)     /* in 4th quadrant */
            qdeg = 360 - qdeg;
    
        rad = qdeg * M_PI / 180.0;      /* convert to radians */
    
        /* compute Taylor-Series expansion for sine for TSLIM / 2 terms */
        for (int n = 2; n < TSLIM; n += 2, sign *= -1) {
            double p = rad;
            uint64_t f = n;
    
            for (int i = 1; i < n; i++)     /* pow */
                p *= rad;
    
            for (int i = 1; i < n; i++)     /* nfact */
                f *= i;
    
            cose_deg += sign * p / f;       /* Taylor-series term */
        }
    
        return pos_quad ? cose_deg : -cose_deg;
    }
    

    发现兔子尾迹...

    【讨论】:

    • 大卫,请您详细说明您是如何到达3e-10 号码的?
    • 当然,这只是在fabs (sin (60 * M_PI/180.0) - sine (60))sine 上方和12DEPTH 的60 度角的快速检查。随着角度的增加,误差会逐渐变大(这将使sine 的计算从0-360 分成象限,就像为atan 所做的那样有利)。 DEPTH20 将在整个0-360 范围内保持误差小于 1.0e-8。使用doublelong double 是无关紧要的`。
    • 感谢您的澄清,但由于库实现不是 sin 的真正价值(它只是一个不同的近似值,可能更好)我会说调用它 differenceerror,因为它可能暗示 3e-10 是与 sin 的真实值之间的理论计算差异。无论如何,再次感谢您向我们解释清楚。
    • 嘿,不错。错误报告仅与 libc sin 认为的角度的 sine 和带有 DEPTH / 2 术语的手动泰勒级数之间的差异一样好。在计算机世界中,归根结底,它都是近似值。使用铅笔和纸以及单位圆,我们可以得到精确的封闭形式表示,使用计算机,它只是沿途过程中固有的所有组合错误的产物:)
    【解决方案4】:

    您的代码中有多个问题:

    • 您使用不同的原型重新定义标准函数pow()。当您将程序链接为可执行文件时,这可能会导致问题。使用其他名称,例如 pow_int

    • 您应该在sine 函数之前将pow_intfact 函数定义为static。它可能允许在编译时进行更好的优化。

    • 确实fact 受到unsigned int 类型范围的限制,它远小于long double 类型的精度。 12 之外的阶乘具有不正确的值,导致精度损失。

    • 您实际上可以增量计算项,从而节省大量计算并避免潜在的精度损失。

    • 不带参数的main() 的原型是int main(void)

    • PI/180 的计算以double 执行,其精度低于long double。你应该把表达式写成x = x * PI / 180;

    • 应增加DEPTH 以提高精度。至少再增加 4 个术语会带来实质性的改善。

    • 您应该应用范围缩减:利用正弦函数对称和周期性的特性,可以在 x 模 90 甚至 45 度上使用更少的项来执行计算。

    这是修改后的版本:

    #include <stdio.h>
    #include <math.h>
    
    #define PI_L   3.14159265358979323846264338327950288L
    #define PI     3.14159265358979323846264338327950288
    #define DEPTH  24
    
    double sine(long double x) {
        long double res, term, x2, t1;
        int phase;
    
        x = remquol(x, 90, &phase);
        if (phase & 1)
            x = 90 - x;
    
        x = x * PI_L / 180; // convert x to radians
        x2 = x * x;         // pre-compute x^2
    
        // compute the sine series: x - x^3/3! + x^5/5! ...
        res = term = x;   // the first term is x
        for (int n = 1; n < DEPTH; n += 4) {
            // to reduce precision loss, compute 2 terms for each iteration
            t1 = term * x2 / ((n + 1) * (n + 2));
            term = t1 * x2 / ((n + 3) * (n + 4));
            // update the result with the difference of the terms
            res += term - t1;
        }
        if (phase & 2)
            res = -res;
    
        return (double)res;
    }
    
    int main(void) {
        printf("deg            sin                  sine         delta\n\n");
        for (int i = 0; i <= 360; i += 10) {
            double s1 = sin(i * PI / 180);
            double s2 = sine(i);
            printf("%3i  %20.17f  %20.17f  %g\n", i, s1, s2, s2 - s1);
        }
        return 0;
    }
    

    输出是:

    deg            sin                  sine         delta
    
      0   0.00000000000000000   0.00000000000000000  0
     10   0.17364817766693033   0.17364817766693036  2.77556e-17
     20   0.34202014332566871   0.34202014332566871  0
     30   0.49999999999999994   0.50000000000000000  5.55112e-17
     40   0.64278760968653925   0.64278760968653936  1.11022e-16
     50   0.76604444311897801   0.76604444311897801  0
     60   0.86602540378443860   0.86602540378443860  0
     70   0.93969262078590832   0.93969262078590843  1.11022e-16
     80   0.98480775301220802   0.98480775301220802  0
     90   1.00000000000000000   1.00000000000000000  0
    100   0.98480775301220802   0.98480775301220802  0
    110   0.93969262078590843   0.93969262078590843  0
    120   0.86602540378443882   0.86602540378443860  -2.22045e-16
    130   0.76604444311897812   0.76604444311897801  -1.11022e-16
    140   0.64278760968653947   0.64278760968653936  -1.11022e-16
    150   0.49999999999999994   0.50000000000000000  5.55112e-17
    160   0.34202014332566888   0.34202014332566871  -1.66533e-16
    170   0.17364817766693025   0.17364817766693036  1.11022e-16
    180   0.00000000000000012  -0.00000000000000000  -1.22465e-16
    190  -0.17364817766693047  -0.17364817766693036  1.11022e-16
    200  -0.34202014332566866  -0.34202014332566871  -5.55112e-17
    210  -0.50000000000000011  -0.50000000000000000  1.11022e-16
    220  -0.64278760968653925  -0.64278760968653936  -1.11022e-16
    230  -0.76604444311897790  -0.76604444311897801  -1.11022e-16
    240  -0.86602540378443837  -0.86602540378443860  -2.22045e-16
    250  -0.93969262078590821  -0.93969262078590843  -2.22045e-16
    260  -0.98480775301220802  -0.98480775301220802  0
    270  -1.00000000000000000  -1.00000000000000000  0
    280  -0.98480775301220813  -0.98480775301220802  1.11022e-16
    290  -0.93969262078590854  -0.93969262078590843  1.11022e-16
    300  -0.86602540378443860  -0.86602540378443860  0
    310  -0.76604444311897812  -0.76604444311897801  1.11022e-16
    320  -0.64278760968653958  -0.64278760968653936  2.22045e-16
    330  -0.50000000000000044  -0.50000000000000000  4.44089e-16
    340  -0.34202014332566855  -0.34202014332566871  -1.66533e-16
    350  -0.17364817766693127  -0.17364817766693036  9.15934e-16
    360  -0.00000000000000024   0.00000000000000000  2.44929e-16
    

    从上面可以看出,sine() 函数似乎比我系统上的标准 sin 函数更精确:sin(180 * M_PI / 128) 应该是 0。同样,sin(150 * M_PI / 128) 应该是 0.5

    【讨论】:

    • 令人印象深刻的实现。如果我可能会问,为什么你在定义上方有一个提升声明?
    • @PatrickRoberts: 好问题:clang -Weverything 对没有看到原型的具有外部链接的函数发出警告。这个警告的目的是确保带有声明的头文件被适当地包含在带有实现的文件中,从而可以验证原型和定义之间的一致性。这里不需要,所以我将其删除。
    【解决方案5】:

    将 main 中的角度范围更改为 -90 到 90 仍将覆盖整个正弦范围。但由于泰勒级数从零开始,深度值可以减少到 7。如前所述,使事实函数 64 位无符号 将解决 67 度问题。

    【讨论】:

      猜你喜欢
      • 2013-07-19
      • 2017-04-10
      • 2017-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多