V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
skywatcher
V2EX  ›  C

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

  •  1
     
  •   skywatcher · 2016-02-21 22:17:39 +08:00 · 1865 次点击
    这是一个创建于 3230 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 ,查了计算精度和编译器有关,不知道能否有效解决。你之前用过?
    mickeyandkaka
        8
    mickeyandkaka  
       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   ·   实用小工具   ·   5609 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 06:40 · PVG 14:40 · LAX 22:40 · JFK 01:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.