Fortran Coder

查看: 10381|回复: 7
打印 上一主题 下一主题

[数学库] Lapack中几个难以理解的现象

[复制链接]

18

帖子

3

主题

0

精华

入门

F 币
93 元
贡献
59 点
跳转到指定楼层
楼主
发表于 2017-8-14 11:39:53 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
最近在编写一个算法时发现了以下两个难以理解的问题:
第一个是使用了write语句输出后会影响后续计算结果。。:

[Fortran] 纯文本查看 复制代码
        write(*,*) resid
          
            call zgeqp3(n, d, resid, n, workint,
     &               workqr,workqr(1+min(n,d)), 
     &      worklen, rwork, info)

           write(*,*) resid



这里zgeqp3是一个计算QR分解的subroutine,是来自于lapack库的。residue作为存放要分解的矩阵,在经过zgeqp3后上三角部分存放得到的R矩阵。
可以看到里面有两处write语句。非常奇怪的是,如果把第一个write语句注释掉,则计算得到的结果residue会出现NAN;反之,如果不注释掉,则计算得到的residue显示正常。这实在难以理解。

第二个是两个数相乘得到了NAN。

[Fortran] 纯文本查看 复制代码
         do 15 i=1, d, 1
             call zcopy(min(d+1-i,nrv),resid(1+(d-i)*n),1,
     &      u(1,(-1+i)*(ncv+1)+1),1) 
             temp1=(1.0d0)/rnorm
         do 16 jj=1, min(d+1-i,nrv)
             write(*,*) u(jj,(i-1)*(ncv+1)+1)
             write(*,*) cmplx(temp1,0.0d0)
             write(*,*) u(jj,
     &      (i-1)*(ncv+1)+1)*cmplx(temp1,0.0d0)  
              u(jj,(i-1)*(ncv+1)+1)=u(jj,
     &     (i-1)*(ncv+1)+1)*cmplx(temp1,0.0d0)     
   16    continue        
   15  continue


这里是将一个矩阵residue复制到另一个矩阵u中,之后再对u中元素乘以一个数。cmplx是使得temp1从实数转为复数。三个write语句输出了每次乘法的过程。结果见图:

可以看到我相乘的两个数中并没有nan,且也不存在0与无穷相乘的情况。但结果却有nan。这对我完全无法理解。。。

我使用的是MinGW编译器。现在程序就耗在这,不止到如何解决。。。如果大家发现了什么问题,能提供相应的思路的话,那就太感谢了。

1.png (10.87 KB, 下载次数: 290)

1.png
分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

沙发
发表于 2017-8-14 12:37:02 | 只看该作者
无法提供可以再现问题的最短fortran代码,就只能对照zgeqp3的函数说明看看有没有参数输入错误
http://www.netlib.org/lapack/exp ... b3f0d9468d99c28d36e

130

帖子

10

主题

0

精华

大师

F 币
617 元
贡献
372 点

贡献勋章管理勋章帅哥勋章元老勋章星光勋章规矩勋章

板凳
发表于 2017-8-14 13:12:27 | 只看该作者
建議試試:
1. compile-time-opions儘量non-optimization
2. 用不同的compilers試試
"lapack库"是用別人的".lib", 還是自己建立的

18

帖子

3

主题

0

精华

入门

F 币
93 元
贡献
59 点
地板
 楼主| 发表于 2017-8-14 13:53:26 | 只看该作者
pasuka 发表于 2017-8-14 12:37
无法提供可以再现问题的最短fortran代码,就只能对照zgeqp3的函数说明看看有没有参数输入错误
http://www.n ...

谢谢,我检查过了,应该是对的。而且我用其他例子简单测试过这个函数的用法,并没有出现相同问题。

18

帖子

3

主题

0

精华

入门

F 币
93 元
贡献
59 点
5#
 楼主| 发表于 2017-8-14 13:54:41 | 只看该作者
pasuka 发表于 2017-8-14 12:37
无法提供可以再现问题的最短fortran代码,就只能对照zgeqp3的函数说明看看有没有参数输入错误
http://www.n ...

而且无论是否出现nan,zgeqp3返回的info都是0,就是说正常结束。。。

18

帖子

3

主题

0

精华

入门

F 币
93 元
贡献
59 点
6#
 楼主| 发表于 2017-8-14 14:31:25 | 只看该作者
chiangtp 发表于 2017-8-14 13:12
建議試試:
1. compile-time-opions儘量non-optimization
2. 用不同的compilers試試

是用别人的lib,具体的说是用如下网址中的“Prebuilt dynamic libraries using Mingw”
http://icl.cs.utk.edu/lapack-for-windows/lapack/#libraries

我也试着用其他的编译器,比如VS的编译器,但是使用时却提示我找不到库函数(无法解析的命令)。。。而我似乎是设置正确的:

6.png (31.11 KB, 下载次数: 276)

6.png

5.png (66.68 KB, 下载次数: 286)

5.png

4.png (63.23 KB, 下载次数: 286)

4.png

3.png (59.55 KB, 下载次数: 280)

3.png

2.png (32.47 KB, 下载次数: 275)

2.png

18

帖子

3

主题

0

精华

入门

F 币
93 元
贡献
59 点
7#
 楼主| 发表于 2017-8-14 17:25:17 | 只看该作者
额!我大概找到原因了,很可能是库文件的问题。。。我刚才换了一个版本的库文件后,这些神奇的现象就都消失了。。具体原因不知道。我猜想的是原来的库文件是专门for windows用户的,而我在编译时是用MinGw的shell,会不会这里出现了问题(这方面我不懂,很可能是瞎想);后来我换的新版本就不是给windows用户的了(且这次库文件是用MinGw编译的,而前面是现成的)。

最后,谢谢大家的关心!

130

帖子

10

主题

0

精华

大师

F 币
617 元
贡献
372 点

贡献勋章管理勋章帅哥勋章元老勋章星光勋章规矩勋章

8#
发表于 2017-8-14 19:42:49 | 只看该作者
恭喜, 解決了問題, 一樂也。

三個可以算是 "难以理解"的, 與君同樂

(a) 光看主程式, "WRITE(*,*) 5", write出來說不是"5", 不可能吧!
[Fortran] 纯文本查看 复制代码
PROGRAM test
  IMPLICIT NONE
  WRITE(*,*) 5
  CALL abc(5)
  WRITE(*,*) 5
  CALL abc(5) 
  WRITE(*,*) 5
CONTAINS
  SUBROUTINE abc(five)
    IMPLICIT NONE
    INTEGER :: five
    five = five + 1
  END SUBROUTINE abc
END PROGRAM test

compile-time給wraning或fatal error, 或是run-time出現不知所云error的, 是"嚴謹"的compilers
run-time告訴你"5"不是"5", 不是Fortran的錯, 也不是compiler的錯(compiler太老實了點), 是程式員的錯(logical error)
compile-time沒任何訊息, run-time告訴你"5"就是"5"的compilers, 太自作聰明了
用Fortrn 90"INTENT"attribute, 是一個好習慣, 但是,  請看 (b)

(b) 光看副程式, 兩個"WRITE(*,*) x", 沒理由值不同吧?
[Fortran] 纯文本查看 复制代码
PROGRAM test
  IMPLICIT NONE
  REAL :: x
  x = 5.0
  CALL abc(x, x) !---> OK, if: CALL ABC((x), x)
CONTAINS
  SUBROUTINE abc(x, y)
    IMPLICIT NONE
    REAL, INTENT(IN   ) :: x
    REAL, INTENT(  OUT) :: y
    WRITE(*,*) 'x=', x
    y = x + 1.0
    WRITE(*,*) 'x=', x
  END SUBROUTINE abc
END PROGRAM test

原因出在主程式 "CALL abc(x, x)"
主/副程式, "語法"都是正確的, 程式員的錯(logical error)
不要以為這是"無聊"的把戲, "x"帶訊息進去責任已了, 能省則省新的訊息由"x"帶出來, 挺合理的
多加一對小括號 "CALL abc((x), x)", 就完全沒問題了

(c) 說一套(syntax defined by language standrad), 做一套(compilation by compiler)
[Fortran] 纯文本查看 复制代码
PROGRAM test
  IMPLICIT NONE
  REAL :: a, b, c
  a=1.0; b=2.0; c=3.0
  CALL abc(a, b, c)
  WRITE(*,*) c
CONTAINS
  SUBROUTINE abc(a, b, c)
    IMPLICIT NONE
    REAL, INTENT(IN   ) :: a
    REAL, INTENT(INOUT) :: b
    REAL, INTENT(  OUT) :: c
    b = a + b
   !WRITE(*,*) c
  END SUBROUTINE abc
END PROGRAM test

! All INTENT(OUT) Dummy Arguments become Undefined on Entry to a Procedure.
! (the intension is that it be used only to pass information out, so it
! becomes undefined on entry to the procedure)
! You cannot use an INTENT(OUT) dummy until it has been defined


(a), (b), (c) compile-time/run-time 會怎樣, compile-time "options" dependent, "compiler" dependent,
甚至會是 compiler "version" dependent, 怎辦? ["SAVE"也是一樣]

不怎辦, 都是程式員的錯 (logical errors)

您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-12-26 19:59

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表