C+中的舍入误差+;建议 我试图在C++中建立一个动态系统,并与存储值的精度有关。

C+中的舍入误差+;建议 我试图在C++中建立一个动态系统,并与存储值的精度有关。,c++,double-precision,C++,Double Precision,我已经阅读了有关浮点精度的文章,但无法找出我的例子中出现了什么问题 所以,问题是关于存储粒子速度。例如,粒子以1.01的速度开始,由于动力系统的性质,它在每次相互作用时只能获得或失去0.4个单位 对于前2890次交互,速度值存储正常(精确到全精度)。在2891次相互作用时,速度变为 4.209999999999999 而不是 4.21 发生这种情况是因为在这一点上,速度第一次达到了一个“丑陋”的值吗?在2890次互动之后 对于这个问题,我有两种可能的解决方法,我想征求您的意见。请记住,我需要

我已经阅读了有关浮点精度的文章,但无法找出我的例子中出现了什么问题

所以,问题是关于存储粒子速度。例如,粒子以1.01的速度开始,由于动力系统的性质,它在每次相互作用时只能获得或失去0.4个单位

对于前2890次交互,速度值存储正常(精确到全精度)。在2891次相互作用时,速度变为

4.209999999999999
而不是

4.21
发生这种情况是因为在这一点上,速度第一次达到了一个“丑陋”的值吗?在2890次互动之后

对于这个问题,我有两种可能的解决方法,我想征求您的意见。请记住,我需要改变初始速度,而不仅仅是使用1.01

  • 更改系统的单位,使其在每次交互时获得或失去1.0的速度。(这会起作用吗?例如,如果起始速度为1.21,它可能会在4.21的值处得到相同的误差?)

  • 每次交互后,将速度四舍五入到某个固定的小数位数。(我不太喜欢这个,因为我必须事先知道速度的精度,这会使程序更笨拙)


  • 感谢您对此可能的想法。

    您好,不确定这是否适合您

    我有个建议给你。由于您正在寻找精度,您可以切换到另一种类型,并使用它而不是双精度。在您的情况下,我要做的是创建一个以不同方式表示双精度值的数据结构,以便它能够保持精度

    Iwillnotexist Idonotexist已经在评论中提到了根本原因。IEEE FP数是二进制分数,4/10不能完全表示为二进制分数,正如1/3不能完全表示为十进制分数一样


    如果您必须坚持FP表示法,并且您愿意更改所使用的值,并且必须具有完美的准确性,那么请坚持使用二进制分数,这些数字可以表示为1/2、1/4、1/8、1/16等的总和

    这些效应是众所周知的“浮点运算”现象。请注意,双精度变量的有效数字约为15:对于大多数物理应用来说,这已经足够了。(例如,已知重力常数的精度远低于此)。不要做任何取整或任何事情:只要学会适应它。@jcoder所以,问题是在大量交互之后,我需要确保我看到的效果是系统的属性,而不是数字噪音。为了检查这一点,我将系统向前传播n个相互作用,然后反向传播速度,并将系统传播额外的n个相互作用-如果代码工作,它应该返回到起点(它不是混沌的)。现在,如果我将它传播到2890次交互,然后再传播回来,它就可以正常工作了。如果我再添加1次交互,则会出现舍入错误,系统会返回到与初始状态非常不同的状态。@mihapriimek完全有可能在第2890次迭代时,您累积了太多错误,而您现在正在提交错误的值。当我检查GDB中的结果时,认为<代码> 1.01 +0.4-0.4+0.4-0.4+0.4-0.4+0.4-0.4…<代码>导致值稳步下降,当您尝试此时,不要用<代码> -OFAST或等效编译,因为该数值重写依赖于编译器不优化<代码> I++;v=1.01+i*0.4向下至
    v+=0.4
    。这被称为强度降低,对于浮点值,正如您刚刚发现的那样,这样做是有害的。MSVC上的开关是
    /fp:precise
    (这是默认值)。在这种情况下,您可能更喜欢
    /fp:strict
    。另一种会是什么样子?它将如何存储值以保持精度?同时告别性能。浮点运算很快。@CodyGray它可以在示例中对字符串或由两个整数组成的分数进行运算。@CodyGray这是一件非常有趣的事情。我在考虑为代表第I位的数字arr[I]创建一个数组,并保留一个整数作为小数点的位置。当然,这会降低性能,但我只是认为,对于真正大的数字,这可能是一个解决方案。告诉我怎么了。:)是的,我觉得它也很有趣。有趣的细节应该在你的答案中。