Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran和Python中的精度和多项式求值_Python_Fortran_Precision_Floating Accuracy_Polynomial Math - Fatal编程技术网

Fortran和Python中的精度和多项式求值

Fortran和Python中的精度和多项式求值,python,fortran,precision,floating-accuracy,polynomial-math,Python,Fortran,Precision,Floating Accuracy,Polynomial Math,我将在这里给出一个快速的描述和下面的上下文。我在Python和Fortran中计算二元多项式(两个变量的多项式),得到不同的结果。我的测试用例-4.23e-3的相对误差足够大,不会因为精度差异而变得明显。下面的代码段使用了相当原始的类型和相同的算法,试图使事情尽可能具有可比性。关于差异有什么线索吗?我尝试过改变精度(在Fortran中使用selected\u real\u kind,在Python中使用numpy.float128),Fortran的编译(特别是优化级别)和算法(Horner的方

我将在这里给出一个快速的描述和下面的上下文。我在Python和Fortran中计算二元多项式(两个变量的多项式),得到不同的结果。我的测试用例-4.23e-3的相对误差足够大,不会因为精度差异而变得明显。下面的代码段使用了相当原始的类型和相同的算法,试图使事情尽可能具有可比性。关于差异有什么线索吗?我尝试过改变精度(在Fortran中使用
selected\u real\u kind
,在Python中使用
numpy.float128
),Fortran的编译(特别是优化级别)和算法(Horner的方法,
numpy
评估)。关于差异有什么线索吗?两个版本的代码中都有错误吗?我已经看过了,但还没有机会完全用不同的编译器来测试它


Python:

#!/usr/bin/env python
""" polytest.py
Test calculation of a bivariate polynomial.
"""

# Define polynomial coefficients
coeffs = (
    (101.34274313967416, 100015.695367145, -2544.5765420363),
    (5.9057834791235253,-270.983805184062,1455.0364540468),
    (-12357.785933039,1455.0364540468,-756.558385769359),
    (736.741204151612,-672.50778314507,499.360390819152)
)
nx = len(coeffs)
ny = len(coeffs[0])

# Values of variables
x0 = 0.0002500000000011937
y0 = -0.0010071334522899211

# Calculate polynomial by looping over powers of x, y
z = 0.
xj = 1.
for j in range(nx):
    yk = 1.
    for k in range(ny):
        curr = coeffs[j][k] * xj * yk
        z += curr
        yk *= y0
    xj *= x0

print(z)   # 0.611782174444

Fortran:

! polytest.F90
! Test calculation of a bivariate polynomial.

program main

  implicit none
  integer, parameter :: dbl = kind(1.d0)
  integer, parameter :: nx = 3, ny = 2
  real(dbl), parameter :: x0 = 0.0002500000000011937, &
                          y0 = -0.0010071334522899211
  real(dbl), dimension(0:nx,0:ny) :: coeffs
  real(dbl) :: z, xj, yk, curr
  integer :: j, k

  ! Define polynomial coefficients
  coeffs(0,0) = 101.34274313967416d0
  coeffs(0,1) = 100015.695367145d0
  coeffs(0,2) = -2544.5765420363d0
  coeffs(1,0) = 5.9057834791235253d0
  coeffs(1,1) = -270.983805184062d0
  coeffs(1,2) = 1455.0364540468d0
  coeffs(2,0) = -12357.785933039d0
  coeffs(2,1) = 1455.0364540468d0
  coeffs(2,2) = -756.558385769359d0
  coeffs(3,0) = 736.741204151612d0
  coeffs(3,1) = -672.50778314507d0
  coeffs(3,2) = 499.360390819152d0

  ! Calculate polynomial by looping over powers of x, y
  z = 0d0
  xj = 1d0
  do j = 0, nx-1
    yk = 1d0
    do k = 0, ny-1
      curr = coeffs(j,k) * xj * yk
      z = z + curr
      yk = yk * y0
    enddo
    xj = xj * x0
  enddo

  ! Print result
  WRITE(*,*) z   ! 0.61436839888538231

end program
编译时使用:
gfortran-O0-o polytest.o polytest.F90


上下文:我正在编写一个现有Fortran库的纯Python实现,主要是作为练习,但也增加了一些灵活性。我正在将我的结果与Fortran进行基准测试,并且已经能够在1e-10范围内获得几乎所有的结果,但这一点超出了我的掌握范围。其他函数也要复杂得多,使得对简单多项式的分歧令人困惑


特定的系数和测试变量来自此库。实际的多项式实际上在(x,y)中有次数(7,6),因此这里没有包括更多的系数。该算法直接取自Fortran,因此,如果算法错误,我应该联系原始开发人员。一般函数也可以计算导数,这就是为什么这个实现可能是次优的一部分——我知道我仍然应该编写一个Horner方法版本,但这并没有改变差异。我只是在计算y的大值的导数时才注意到这些错误,但这个错误确实存在于这个更简单的设置中。

Fortran代码中的两件事应该得到纠正,以使结果在Python和Fortran版本之间匹配

1。正如您所做的那样,声明一种特定的双精度类型,如下所示:

integer, parameter :: dbl = kind(0.d0)
然后,应通过添加种类指示符来定义变量,如下所示:

real(dbl) :: z
z = 1.0_dbl
例如,在fortran90.org上讨论了这一点。语法可能不方便,但嘿,规则不是我定的

2.Fortran do循环迭代由
nx
ny
控制。您打算访问
coefs
的每个元素,但您的索引缩短了迭代。将
nx-1
ny-1
分别更改为
nx
ny
。更好的方法是,使用Fortran内在的
ubound
来确定沿所需维度的范围,例如:

do j = 0, ubound(coeffs, dim=1)
下面显示的更新代码纠正了这些问题,并打印出与python代码生成的结果相匹配的结果

program main
    implicit none
    integer, parameter :: dbl = kind(1.d0)
    integer, parameter :: nx = 3, ny = 2
    real(dbl), parameter :: x0 = 0.0002500000000011937_dbl, &
                          y0 = -0.0010071334522899211_dbl
    real(dbl), dimension(0:nx,0:ny) :: coeffs
    real(dbl) :: z, xj, yk, curr
    integer :: j, k

    ! Define polynomial coefficients
    coeffs(0,0) = 101.34274313967416_dbl
    coeffs(0,1) = 100015.695367145_dbl
    coeffs(0,2) = -2544.5765420363_dbl
    coeffs(1,0) = 5.9057834791235253_dbl
    coeffs(1,1) = -270.983805184062_dbl
    coeffs(1,2) = 1455.0364540468_dbl
    coeffs(2,0) = -12357.785933039_dbl
    coeffs(2,1) = 1455.0364540468_dbl
    coeffs(2,2) = -756.558385769359_dbl
    coeffs(3,0) = 736.741204151612_dbl
    coeffs(3,1) = -672.50778314507_dbl
    coeffs(3,2) = 499.360390819152_dbl

    ! Calculate polynomial by looping over powers of x, y
    z = 0.0_dbl
    xj = 1.0_dbl
    do j = 0, ubound(coeffs, dim=1)
        yk = 1.0_dbl
        do k = 0, ubound(coeffs, dim=2)
            print "(a,i0,a,i0,a)", "COEFF(",j,",",k,")="
            print *, coeffs(j,k)
            curr = coeffs(j,k) * xj * yk
            z = z + curr
            yk = yk * y0
        enddo
        xj = xj * x0
    enddo

    ! Print result
    WRITE(*,*) z   ! Result: 0.611782174443735
end program  

如果它们都是相同的算法,您应该能够比较两个实现之间的中间值,以查看差异的进展情况,如果存在“罪魁祸首”,请确定它。我已经很久没有看过Fortran代码了,但看起来您的循环边界不同。例如,在fortran代码中,
j
将从
0->2(nx-1)
。在python代码中,
j
是从
0->3(len(coeffs)-1)
开始的,在Fortran中,您只将参数x0和y0设置为单精度。此外,常数的规格说明是非常老式(f77)风格和更现代的使用种类值的奇怪混合。此外,我认为@mgilson发现了错误。感谢您捕捉到这个错误!我一直在多项式求值作为一个单独的函数(读取系数数组的形状,这是一个输入)和这个版本之间来回切换,以使其尽可能简单(其中nx,ny已经给出)。
1.0d0
1.0_dbl
这两个方面可能解释了我在使用更高功率时所遇到的差异,我将在下一步进行测试。无论如何,那将是一个单独的问题。没问题。
1.0d0
1.0_dbl
给出了相同的精度,因为您已将
dbl
定义为相同的类型,但只是为了保持一致……很明显,精度损失发生在参数的定义上;ie
real(dbl),参数::x0=0.000250000000011937
有效地创建一个精度值。尝试打印该值,并在使用
\u dbl
时与进行比较。这里的教训是,为了保持双精度,必须附加描述符
\u dbl
,甚至
.d0
。我真的不知道这个效果是如何成为一个有用的特性,也许其他人可以给我们一些启示。默认情况下,数字文字为单精度;正如您所解释的,如果您还需要其他内容,您需要附加适当的类型说明符。要清楚:我把
d0
x0
中去掉了,把事情搞砸了。但是原始代码定义了
dbl=selected\u real\u kind(p=15,r=307)
,但仍然用
d0
而不是
\u dbl
附加它们的文本。这是一种糟糕的做法,但它会有精度损失吗?在完整的多项式计算中,我仍然会遇到分歧(即使在将大部分
d0
s更改为
\u dbl
s之后),但我还没有一个MWE。