代码之家  ›  专栏  ›  技术社区  ›  Josh Kelley

sin、cos、tan和舍入误差

  •  4
  • Josh Kelley  · 技术社区  · 15 年前

    我在C/C++中做一些三角计算,并且遇到四舍五入错误的问题。例如,在我的Linux系统上:

    #include <stdio.h>
    #include <math.h>
    
    int main(int argc, char *argv[]) {
        printf("%e\n", sin(M_PI));
        return 0;
    }
    

    此程序提供以下输出:

    1.224647e-16
    

    当正确答案为0时。

    当使用trig函数时,我可以期望有多少舍入误差?我如何才能最好地处理这个错误?我熟悉最后一位的单位比较浮点数的技术,来自布鲁斯·道森的 Comparing Floating Point Numbers 但这似乎不起作用,因为0和1.22E-16相距相当大。

    9 回复  |  直到 6 年前
        1
  •  12
  •   Andy Ross    15 年前

    IEEE双存储52位尾数,带有“隐式前导” 一个“形成53位数字。结果底端的错误 因此,约占数字比例的1/2^53。你的输出是 与1.0的顺序相同,所以结果只有一个 10^16部分(因为53*log(2)/log(10)=15.9)。

    所以是的。这是关于精度的极限。我是 不知道你用的是什么超低频技术,但我怀疑你 应用错误。

        2
  •  13
  •   Martin Beckett    15 年前

    对于sin(pi),答案只有0——你包括了pi的所有数字吗?

    -有没有其他人注意到这里明显缺乏讽刺/幽默感?

        3
  •  6
  •   Martin Beckett    15 年前

    @乔希·凯利-好的,严肃的回答。
    一般来说,不应该将涉及浮点或双精度的任何操作的结果相互比较。

    唯一的例外是分配。
    浮动A=10;
    浮动B=10;
    然后A==B

    否则,您总是需要编写一些函数,如bool isclose(float a、float b、float error),以便检查两个数字是否在彼此的“错误”范围内。
    记住还要检查标志/使用FABS-您可以-1.224647E-16

        4
  •  6
  •   chux - Reinstate Monica    6 年前

    _的正弦值为0.0。
    sine of m_pi is about 1.224647E-16.

    m_pi is not_.

    < Buff行情>

    程序给出…1.224647E-16,正确答案当然是0。

    < /块引用>

    代码对7个位置给出了正确的答案。


    以下内容不打印 它打印出一个接近_的数字的正弦值。见下图。

    _//3.14159265358979323846264333832795…
    printf(“%.21\n”,m_pi);//3.141592653589793115998
    printf(“%.21f\n”,sin(m_pi));//0.000000000000000122465
    < /代码> 
    
    

    注:使用数学函数sine(x).,曲线的斜率为-1.0 atx=_.。_和m_-pi的区别是about thesin(m_-pi).-as expected.


    < Buff行情>

    遇到舍入错误的问题

    当使用m_pito present_时,会出现舍入问题。m_piis thedoubleclosest to_,yet since_is increasible and all fermeddoubleare rational,they must difference-even by a small amount.因此,对于sin(),cos(),tan()不是直接的舍入问题。sin(m_pi)simple exposed the issue started with using an inexact_。


    如果代码使用了不同的fp类型,则会出现此问题,其非零结果分别为sin(m_pi).,如float.,long double.double.with something other than 53 binary bits of precision.这不是一个精确的问题,而是一个非理性/理性的问题。

    MYPI不是γ。

    程序给出…1.224647E-16,正确答案当然是0。

    代码给出了7个正确的答案。


    以下内容不打印π. 它打印出一个接近_的数字的正弦值。请看下面的图片。

    π                            // 3.1415926535897932384626433832795...
    printf("%.21\n", M_PI);      // 3.141592653589793115998
    printf("%.21f\n", sin(M_PI));// 0.000000000000000122465
    

    注:使用数学函数正弦(x),曲线的斜率为-1.0x=α. _和MYPI是关于sin(M_PI)-如期.


    遇到舍入错误的问题

    使用时出现舍入问题MYPI呈现。MYPIdouble最接近_,但因为_是无理的,而且都是有限的。双重的是理性的,他们必须有所不同——即使只是一小部分。所以不是直接的四舍五入问题sin(), cos(), tan().罪恶(MYPI)Simple暴露了这个问题,从使用不精确的_开始。


    这个问题,有不同的非零结果罪恶(MYPI),如果代码使用不同的fp类型,如float,long double双重的除了53个二进制位的精度。这不是一个精确的问题,而是一个非理性/理性的问题。

    Sine(x) near π

        5
  •  1
  •   Clifford    15 年前

    错误有两个来源。sin()函数和m_pi的近似值。即使sin()函数是“完美的”,它也不会返回零,除非m_pi的值也是完美的——而事实并非如此。

        6
  •  0
  •   David Thornley    15 年前

    我宁愿认为这取决于系统。我认为这个标准没有任何关于超验函数有多精确的说法。不幸的是,我不记得看到任何关于函数精度的讨论,所以您可能需要自己解决。

        7
  •  0
  •   Kimvais    15 年前

    我在我的系统上得到了完全相同的结果-我会说它足够近了

    我将通过将格式字符串更改为“%f\n”:来解决此问题。

    但是,这会给您一个“更好”的结果,或者至少在我的系统中,它会给-3.661369E-245

    #include <stdio.h>
    #include <math.h>
    
    int main(int argc, char *argv[]) {
        printf("%e\n", (long double)sin(M_PI));
        return 0;
    }
    
        8
  •  0
  •   Matt Pascoe    15 年前

    除非您的程序需要有效数字到小数点后16位或更多,否则您可能可以手动进行舍入。根据我编程游戏的经验,我们总是把小数四舍五入到一个可以接受的有效数字。例如:

    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define HALF 0.5
    #define GREATER_EQUAL_HALF(X) (X) >= HALF
    
    double const M_PI = 2 * acos(0.0);
    
    double round(double val, unsigned  places = 1) 
    {
        val = val * pow(10.0f, (float)places);
        long longval = (long)val;
        if ( GREATER_EQUAL_HALF(val - longval) ) {
           return ceil(val) / pow(10.0f, (float)places);
        } else {
          return floor(val) / pow(10.0f, (float)places);
        }
    }
    
    int main() 
    {
        printf("\nValue %lf", round(sin(M_PI), 10));
        return 0;
    }
    
        9
  •  -1
  •   ralf htp    6 年前

    可能实施的准确性太低

    M_PI = 3.14159265358979323846 (20 digits)
    

    http://fresh2refresh.com/c/c-function/c-math-h-library-functions/