比较用两种不同语言执行的数学运算之间的数值结果

时间:2018-03-05 13:46:38

标签: python precision numerical-methods idl-programming-language

我目前正在尝试将算法从IDL移植到Python 3,在比较结果时,我遇到了以下问题:如何查看数字并确定我是否有效地再现结果?

假设不同的语言在指向浮点精度方面的处理方式稍有不同,预计结果应该有点不同,但到目前为止这是可以接受的?

在下图中,我将使用IDL和python生成的数据集的平均值来说明我的观点:

Mean values of the respective arrays

虽然在一些计算中我可以看到其他人的价值相似,但他们并没有达到标准。

查看下面的步骤,其中将使用将要使用的矩阵集的跟踪来确定解决方案是否存在问题,我对IDL和Python都有以下结果:

Trace

看起来相当不错(我可以这么说吗?)。

然后重新组织计算此迹线的(100,y维,x维)矩阵,以计算最小二乘拟合,最终将产生将创建均值的值。

我使用这些比较来查找有关python版本需要更改和改进的线索,因此我感谢任何可以引导我朝这个方向发展的想法。

提前感谢你的时间。

2 个答案:

答案 0 :(得分:1)

每个数字表示在计算过程中注入两个量:
- 一些(由数字表示的主要数量)
- 一些错误(次要数量,作为副作用,由数字表示引起)

没有前者(The Value ...)

,任何人都无法计算

没有人可以逃避后者,实际上可见,因为(i-)负责计算过程流程的最终结果错误(更好的累积不确定性水平)。

没有太多策略可以应对简化"普通"中嵌入的主要错误(不确定性)。代表性,由IEEE-754(-1985)提倡。

然而,有许多科学领域,其中具有如此快速降低的结果精度的数值方法是不够的。 。 。所以?

无论是天文学,还是行星际飞行动力学计算,有些情况下,IEEE-754数字很快就无法提供可接受的服务。

这里的计算工具提供了一些可供选择的解决方案。

>>> import decimal
>>> 
>>> with decimal.localcontext() as locCTX:
...      for aPREC in range( 20, 31 ):
...          locCTX.prec = aPREC
...          ( pure_dec_LSQ_5DoF( locCTX, dec_fmin_x0_SEARCH_TRIM_TO_BE_PRECISE, decX, decY ), pure_dec_RESi( locCTX, dec_fmin_x0_SEARCH_TRIM_TO_BE_PRECISE, decX, decY ) )
...
(Decimal('0.038471115298826195147'),           (Decimal('0.023589050081780503'),           Decimal('-0.082605913918299990'),           Decimal('0.150647690402532134'),           Decimal('-0.091630826566012630')))
(Decimal('0.0384711152988261953165'),          (Decimal('0.0235890500817804889'),          Decimal('-0.0826059139182999933'),          Decimal('0.1506476904025321349'),          Decimal('-0.0916308265660126301')))
(Decimal('0.03847111529882619531420'),         (Decimal('0.02358905008178048823'),         Decimal('-0.08260591391829999331'),         Decimal('0.15064769040253213501'),         Decimal('-0.09163082656601263007')))
(Decimal('0.038471115298826195324048'),        (Decimal('0.023589050081780488368'),        Decimal('-0.082605913918299993309'),        Decimal('0.150647690402532135021'),        Decimal('-0.091630826566012630071')))
(Decimal('0.0384711152988261953231489'),       (Decimal('0.0235890500817804883582'),       Decimal('-0.0826059139182999933087'),       Decimal('0.1506476904025321350199'),       Decimal('-0.0916308265660126300707')))
(Decimal('0.03847111529882619532322276'),      (Decimal('0.02358905008178048835950'),      Decimal('-0.08260591391829999330863'),      Decimal('0.15064769040253213501998'),      Decimal('-0.09163082656601263007070')))
(Decimal('0.038471115298826195323213788'),     (Decimal('0.023589050081780488359358'),     Decimal('-0.082605913918299993308625'),     Decimal('0.150647690402532135019974'),     Decimal('-0.091630826566012630070702')))
(Decimal('0.0384711152988261953232136753'),    (Decimal('0.0235890500817804883593541'),    Decimal('-0.0826059139182999933086251'),    Decimal('0.1506476904025321350199740'),    Decimal('-0.0916308265660126300707023')))
(Decimal('0.03847111529882619532321367314'),   (Decimal('0.02358905008178048835935336'),   Decimal('-0.08260591391829999330862505'),   Decimal('0.15064769040253213501997413'),   Decimal('-0.09163082656601263007070231')))
(Decimal('0.038471115298826195323213665675'),  (Decimal('0.023589050081780488359353229'),  Decimal('-0.082605913918299993308625043'),  Decimal('0.150647690402532135019974132'),  Decimal('-0.091630826566012630070702306')))
(Decimal('0.0384711152988261953232136649869'), (Decimal('0.0235890500817804883593532187'), Decimal('-0.0826059139182999933086250437'), Decimal('0.1506476904025321350199741307'), Decimal('-0.0916308265660126300707023064')))

Python很高兴享受 几乎 - 无限精确数学,所以最简单的一步就是重新设计python方面的算法,因此它纯粹包含了这种几乎 - 非降级精度数学,你突然站在更安全的一面,独立于IDL原始的位置。 / p>

鉴于我们以这种精确的非降级方式重新制定了所有计算步骤,结果值得花时间:

def pure_dec_LSQ_5DoF(   decCTX,                                                Xopt,                                                decX_measured,                            decY_measured ):                            # [PERF] ~ 2400 [us] @ .prec =   14
    return decCTX.add(   decCTX.add( decCTX.power( decCTX.subtract( decCTX.fma( Xopt[0], decCTX.power( Xopt[4], decCTX.fma( Xopt[1], decX_measured[0], Xopt[2] ) ), Xopt[3] ), decY_measured[0] ), decimal.Decimal( 2 ) ), #        ~ 2800 [us] @ .prec =   28
                                     decCTX.power( decCTX.subtract( decCTX.fma( Xopt[0], decCTX.power( Xopt[4], decCTX.fma( Xopt[1], decX_measured[1], Xopt[2] ) ), Xopt[3] ), decY_measured[1] ), decimal.Decimal( 2 ) )  #        ~ 7700 [us] @ .prec =  100
                                     ),
                         """                                                        [0]                    [4]                  [1]                        [2]          [3]        _measured[i] ~ [X1,Y1], ...
                                                                                     |                      |                    |                          |            |                                  
                                                                                     |                      |                    |                          |            |         Xopt[0,1,2,3,4] ~ [a,b,c,d,f]
                                                                                     |                      |                    |                          |            |                            | | | | |
                                                                                     +----------------------|--------------------|--------------------------|------------|----------------------------+ | | | |
                                                                                                            |                    +--------------------------|------------|------------------------------+ | | |
                                                                                                            |                                               +------------|--------------------------------+ | |
                                                                                                            |                                                            +----------------------------------+ |
                                                                                                            +-------------------------------------------------------------------------------------------------+
                         """                                                                                                                                                                                    
                         decCTX.add( decCTX.power( decCTX.subtract( decCTX.fma( Xopt[0], decCTX.power( Xopt[4], decCTX.fma( Xopt[1], decX_measured[2], Xopt[2] ) ), Xopt[3] ), decY_measured[2] ), decimal.Decimal( 2 ) ), #        ~ 1340 [ms] @ .prec = 1000
                                     decCTX.power( decCTX.subtract( decCTX.fma( Xopt[0], decCTX.power( Xopt[4], decCTX.fma( Xopt[1], decX_measured[3], Xopt[2] ) ), Xopt[3] ), decY_measured[3] ), decimal.Decimal( 2 ) )  #
                                     )
                         )

如果需要~ 14 - 数字精确度,则只需花费~ 2.4 [ms]每个步骤, 如果需要~ 28 - 数字精确度,只需花费~ 2.8 [ms]每个步骤,
如果需要~100 - 数字精确度,只需花费~ 7.7 [ms]每个步骤,
如果需要1000 - 数字精确度,只需花费~ 1.3 [ s]每个步骤,
一点也不差,
是吗?

# [PERF] ~ 2400 [us] @ .prec =   14
#        ~ 2800 [us] @ .prec =   28
#        ~ 7700 [us] @ .prec =  100
#        ~ 1340 [ms] @ .prec = 1000

这些已经包含在python工具中并且很难重复使用,不是吗?

答案 1 :(得分:1)

真正的问题不是如果不同的实现给你相似的值,这可能会让你觉得他们是对的。

真正的问题是这些价值观是否有意义!