sin, cos, tan not accurate

柔情痞子 提交于 2020-04-29 15:51:26

问题


Why does sinl give incorrect results when the argument is near a non-zero multiple of pi? Why does sinl give incorrect results when the argument is large? The following code illustrates that.

Note that the digits used to initialize variable pi do not exactly match any 64-bit long double value. The compiler chooses the nearest value, which is 3.14159265358979323851280895940618620443274267017841339111328125. The expected sine value can be found using libquadmath, gnu MPFR lib, or an online calculator such as http://www.ttmath.org/online_calculator.

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

int main (int argc, char *argv [])
    {
    volatile long double pi = 3.14159265358979323846L;
    volatile long double big = 9223372035086174241L;
    volatile long double expected1 = -5.0165576126683320235E-20L;
    volatile long double expected2 = -4.2053336735954077951E-10L;
    double result;
    double ex1 = expected1, ex2 = expected2;

    result = sinl (pi);
    printf("expected: %g, \nreturned: %g\n\n", ex1, result);
    result = sinl (big);
    printf("expected: %g, \nreturned: %g\n\n", ex2, result);
    return 0;
    }

I am using gcc 4.7.3. The use of volatile keeps the compiler from replacing the sinl() call with a hard-coding result. My computer has an Intel Core i7 processor and runs Windows. I am printing the results as double instead of long double because the mingw port of gcc I use does not support printing long double. Here is the program output:

expected: -5.01656e-020,
returned: -5.42101e-020

expected: -4.20533e-010,
returned: -0.011874

回答1:


The inaccuracy can be traced to the fsin processor instruction used by the sinl library code. The instructions fsin, fcos, and fptan are not accurate to 1.0 ulp as Intel claims: http://notabs.org/fpuaccuracy/




回答2:


In order to achieve 1 ULP accuracy for multiples of pi, the internal constant M_PI should have about 106 bit accuracy (or 128 for long doubles).

In the reduction stage a perfect implementation would have to somehow generate the missing 53 or 64 bits of accuracy after subtracting (x - M_PI), as an naive implementation would calculate this interim value as zero. The problem of course gets bigger and bigger, when the argument will be a large integer multiply of that non-zero.

The internal precision of 66 bits for M_PI is not enough for 1 ULP accuracy. Then again, one could re-read the claims and check if the accuracy of 1 ULP was claimed relative to the result, or the argument.




回答3:


GNU libc's documentation (accessible by running info libc math errors) lists a 1 ulp "known error" for cosl on x86 and "x86_64/fpu." It doesn't document anything for sinl. I can reproduce similarly huge errors for cosl around pi/2 on my x86_64 machine.

Perhaps you should report this as a documentation bug to the glibc and Linux man pages folks; I can't imagine it's worth implementing the "right" fix.

If you really want a fast and accurate sinl, I'm not too sure where to look. CRlibm does sin (the variant for doubles). MPFR will handle it, but it'll be many times slower than fsin.



来源:https://stackoverflow.com/questions/16880376/sin-cos-tan-not-accurate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!