澄清fortran隐含的循环 [英] Clarifying a fortran implied loop

查看:243
本文介绍了澄清fortran隐含的循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我多年前使用了FORTRAN,最近被授权维护一个旧的FORTRAN程序(F77)。以下代码是不熟悉的:

  READ(FILE_LOG_UNIT,IOSTAT = FILE_STATUS)NUM_WORDS,
。 (BUFFER(BIX),BIX = 1,NUM_WORDS)

回顾一些在线论坛,让我困惑的部分,延续线,是一个隐含的循环。由于我的程序在这里给我带来了麻烦,我想将其转换为传统的DO循环。转换它也可能有助于下一个可怜的懒汉,从现在开始,这件事情会在5年后变冷!无论如何,我在DO循环等效方面的最佳猜测是:

$ $ p $ READ(FILE_LOG_UNIT,IOSTAT = FILE_STATUS)NUM_WORDS
DO BIX = 1,NUM_WORDS
READ(FILE_LOG_UNIT,IOSTAT = FILE_STATUS)BUFFER(BIX)
ENDDO

但是,当我仅做出这种更改时,正在工作的测试用例停止工作。我仍然觉得这里发生的是两个不同的READ(第一个获取NUM_WORDS,第二个读取数据),所以我尝试了一个不太剧烈的改变,将其转换为两个语句,但保留了隐含的循环:

  READ(FILE_LOG_UNIT,IOSTAT = FILE_STATUS)NUM_WORDS 
READ(FILE_LOG_UNIT,IOSTAT = FILE_STATUS)(BUFFER(BIX), BIX = 1,NUM_WORDS)

但是这种改变也会导致很好的测试用例失败。在我的两个改动中,NUM_WORDS的值都像预期的那样通过了,所以看起来循环是失败的地方。

那么,什么是等效的DO原始隐含循环的循环?或者我在错误的轨道上完全?

谢谢

解决方案

文件是如何打开的?即是ACCESS ='sequential',access ='direct'还是access ='stream'(好吧,最后一个不太可能,因为它是F2003的补充)。其次,它是格式化还是非格式化的?我将假设它是无格式的顺序,因为在你的read语句中没有REC =说明符或格式说明符。



你试图失败的原因每个读取语句读取一个单独的记录。在F2003中引入access ='stream'之前,Fortran I / O是完全基于记录的,这与我们用于流式类型文件的流程略有不同,如大多数其他语言中所见。

无格式连续文件的记录通常在记录的每一端由记录标记分隔,通常是4个字节,用于指定记录的长度。因此,记录(在磁盘上)可能看起来像



|长度(4字节)| num_words(4字节?)|缓冲区(1)|缓冲区(2)| ... |长度|

现在,如果您尝试读取带有一个READ语句的num_words,它将正确地从该文件中读取num_words,然后它将跳过直到开始下一个记录。然后,当您尝试使用单独的READ语句读取缓冲区时,您在文件中已经遥遥领先。



如果您作弊并使用F90 +数组语法, (FILE_LOG_UNIT,IOSTAT = FILE_STATUS)NUM_WORDS,BUFFER(1:NUM_WORDS)


  / code> 

(尽管我不确定是否允许在正在写入的同一语句中引用num_words) / p>

I used FORTRAN a little, many years ago, and have recently been tasked to maintain an old FORTRAN program (F77). The following code was unfamiliar:

      READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS,  
   .    ( BUFFER(BIX), BIX=1, NUM_WORDS )  

Reviewing some on-line forums revealed that the part that was confusing me, the continuation line, is an implied loop. Since my program is giving me trouble right here, I want to convert this to a conventional DO-loop. Converting it might also help the next poor slob that picks this thing up cold 5 years from now! Anyway, my best guess at the DO-loop equivalent is

  READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS  
  DO BIX=1, NUM_WORDS  
    READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) BUFFER(BIX)  
  ENDDO  

But when I made only this change, test cases which were working stopped working. I still felt that what was going on here was two different READs (the first to get NUM_WORDS, and the second to loop through the data), so I tried a less drastic change, converting it to two statements but retaining the implied loop:

  READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS  
  READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) ( BUFFER(BIX), BIX=1, NUM_WORDS )  

But just this change also causes the good test cases to fail. In both of my alterations, the value of NUM_WORDS was coming through as expected, so it seems that the loop is where it is failing.

So, what is the equivalent DO-loop for the original implied loop? Or am I on the wrong track altogether?
Thanks

解决方案

How is the file opened? I.e. is it ACCESS='sequential', access='direct', or access='stream' (well, the last is unlikely as it's a F2003 addition). Secondly, is it formatted or unformatted? I'm going to assume it's unformatted sequential since there is no REC= specifier nor a format specifier in your read statements.

The reason why what you're trying to fails is that each read statement reads a separate record. Prior to the introduction of access='stream' in F2003, Fortran I/O was completely record based, which is slightly alien to those of us used to stream type files as seen in most other languages.

Records for unformatted sequential files are typically separated by "record markers" at each end of the record, typically 4 bytes specifying the length of the record. So the record (on disk) likely looks something like

| length (4 bytes) | num_words (4 bytes?) | buffer(1) | buffer(2) | ... | length |

Now if you try to read, say, num_words with one READ statement, it will correctly read num_words from the file, THEN it will skip forward until the start of the next record. And when you then try to read buffer with a separate READ statement you're already too far ahead in the file.

If you cheat a bit and use F90+ array syntax, you might get away with

READ(FILE_LOG_UNIT, IOSTAT=FILE_STATUS) NUM_WORDS, BUFFER(1:NUM_WORDS)

(though I'm not sure if you're allowed to reference num_words in the same statement where it's being written to)

这篇关于澄清fortran隐含的循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆