如何解决 C++中三角函数和计算带来的误差? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
skywatcher
V2EX    C

如何解决 C++中三角函数和计算带来的误差?

  •  1
     
  •   skywatcher 2016-02-21 22:17:39 +08:00 2330 次点击
    这是一个创建于 3577 天前的主题,其中的信息可能已经有所发展或是发生改变。
    double a = sqrt(2)/2 = 0.70710678118654746 double b = acos(a) = 1.5707963267948966 double c = sin(b) = 0.70710678125004089 

    如何减小 a 和 c 之间的误差?

    17 条回复    2016-02-22 14:23:05 +08:00
    Neveroldmilk
        1
    Neveroldmilk  
       2016-02-21 22:58:58 +08:00
    不用减小,只需要设立一个很小的 double 数值来判断两个 double 值是否相等。这是对比浮点数的基本操作。
    6god
        2
    6god  
       2016-02-21 23:05:13 +08:00 via iPad
    Numerical method 中的 loss of significance. 别问我具体是啥 只知道章节 不会用啊
    Changxu
        3
    Changxu  
       2016-02-21 23:09:58 +08:00
    误差可能来自两方面: 1 、函数泰勒级数展开项不够多,这个可以改写函数,使用更多的级数来展开; 2 、 double 类型运算 /精度误差,请参考 IEEE 754 标准,这个误差就得使用高精度运算等来解决了
    MCVector
        4
    MCVector  
       2016-02-21 23:35:28 +08:00
    试试 long double? sqrt(2.0L)
    skywatcher
        5
    skywatcher  
    OP
       2016-02-21 23:43:31 +08:00
    @Neveroldmilk 我知道可以自己根据精度写个 equal 函数,但是我想要更高的精度
    skywatcher
        6
    skywatcher  
    OP
       2016-02-21 23:44:20 +08:00
    @MCVector 提问之前已测试过无效
    skywatcher
        7
    skywatcher  
    OP
       2016-02-21 23:46:59 +08:00
    @Changxu 3q ,查了计算精度和编译器有关,不知道能否有效解决。你之前用过?
    valuedlute
        8
    valuedlute  
       2016-02-21 23:47:49 +08:00
    libgmp
    skywatcher
        9
    skywatcher  
    OP
       2016-02-21 23:48:44 +08:00
    @6god 我查查
    SoloCompany
        10
    SoloCompany  
       2016-02-22 01:35:30 +08:00
    http://stackoverflow.com/questions/4818573/accuracy-of-long-double-sqrt

    撸主你有点懒啊,我还是帮你一下吧,用 std::sqrt 可破
    starqoq
        11
    starqoq  
       2016-02-22 09:55:15 +08:00
    也可以使用符号计算库。

    http://www.ginac.de/tutorial/#How-to-use-it-from-within-C_002b_002b

    (我用过 python 的 sympy ,但是没有用过这个)
    Changxu
        12
    Changxu  
       2016-02-22 12:47:01 +08:00
    @skywatcher 没,我使用过程中对精度要求没有那么高,一般误差在 1e-7 以下就可以忽略了
    ilotuo
        13
    ilotuo  
       2016-02-22 13:13:15 +08:00
    自己实现一个泰勒展开~
    mko0okmko0
        14
    mko0okmko0  
       2016-02-22 13:14:52 +08:00   1
    编译器中与浮点精度有关的参数,你的程式码用 gcc 编译时试着加入看看?
    -mfpmath=sse
    -msseregparm
    -m128bit-long-double
    -mlong-double-128
    -mpc80
    -mrecip=?
    -ffloat-store
    -fexcess-precision=?
    -ffast-math=?
    -fno-math-errno
    -fsingle-precision-constant

    https://gcc.gnu.org/onlinedocs/gcc-4.9.3/gcc/Floating-point-implementation.html#Floating-point-implementation

    https://gcc.gnu.org/onlinedocs/gcc-4.9.3/gcc/i386-and-x86-64-Options.html#i386-and-x86-64-Options

    另外提示你,C(++)浮点计算是有明确规范舍入误差的,就像 php/js 一样.
    但有很多库或是变换方法可计算指定位数舍入 /方式,或是科学库近乎无损的.
    你可以找无损计算科学库.然后注意这些库的编译参数条件(就上面那些还有更多)的指定要求.
    skywatcher
        15
    skywatcher  
    OP
       2016-02-22 13:54:26 +08:00
    @6god 看了一下,通过变换表达式来避免误差,很有意思!
    skywatcher
        16
    skywatcher  
    OP
       2016-02-22 14:17:02 +08:00
    @mko0okmko0
    @starqoq
    @mickeyandkaka

    非常感谢,这几个库都已经能达到很高的精度了!
    skywatcher
        17
    skywatcher  
    OP
       2016-02-22 14:23:05 +08:00
    非常感谢!
    @SoloCompany 表示 std::sqrt 并未带来优势
    @MCVector long double 确实改进了(之前输入参数没注意)
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     769 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 21:10 PVG 05:10 LAX 13:10 JFK 16:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86