Storage Informer
Storage Informer

Doctor Fortran in “Revert! Revert! The End (of the format) is Nigh!”

by on Jul.01, 2009, under Storage

Doctor Fortran in “Revert! Revert! The End (of the format) is Nigh!”

Recently, a customer wrote in our User Forums that he wanted to write out the values of an array, all in one line, where the number of elements was not known at compile time.  His first attempt at this was:

write (30,&apos(2x,f8.2)&apos) array

and he was dismayed to find each element written on a new line.  He had then tried this variant:

write (30,&apos(2x,f8.2)&apos,advance=&aposno&apos) array

reasoning that the "advance=&aposno&apos" would prevent the new lines.  No good – still one element per line.

Another user suggested this:

write (30,&apos(2x,(f8.2))&apos) array

but this was worse in that the first line had two spaces before the number but subsequent lines did not.

What&aposs happening here?  What is the best way to write a format that will give a specific format to a variable number of values?

Bouncing off a hard, rubber wall

The odd behavior is due to a little-understood Fortran language feature called "format reversion".  This dates back to at least Fortran 77, if not Fortran IV, and specifies what happens when you get to the end of the format but still have items to process.  A new record is started, (technically, it behaves as if a &apos/&apos edit descriptor was processed), and "format control then reverts back to the beginning of the format item terminated by the last preceding right parenthesis… If there is no such preceding right parenthesis, format control reverts to the first left parenthesis of the format specification."

If we take the original format above,

&apos(2x,f8.2)&apos

and assume that the array has three elements, this ends up being equivalent to:

&apos(2x,f8.2/2x,f8.2/2x,f8.2)&apos

because there is no preceding right parenthesis, so control reverts back to the beginning of the format and three records will be created.  Even if advance=&aposno&apos is added, we&aposll get three records because "non-advancing I/O" is about what happens at the end of the I/O statement, not the middle of it.

Now let&aposs look at the proposed fix:

&apos(2x,(f8.2))&apos

This ends up being equivalent to:

&apos(2x,f8.2/f8.2/f8.2)&apos

as the end of the (f8.2) group is the preceding right parenthesis, so we revert to the beginning of that group. By the way, if there is a repeat count on that group, then the repeat count gets reused.

What to do, what to do

In Fortran 2003, there&aposs no really good way of generally attacking this problem.  If you have an idea of an upper limit for the number of elements, you could specify a large repeat count on the group, such as:

&apos(1000(2x,f8.2))&apos

This assumes there won&apost be more than 1000 elements, but is somewhat ugly.  And no, you can&apost put a PARAMETER constant in for the 1000.  Some people will suggest that you construct a format at run-time by writing into a character variable and using a run-time format, like so:

character(80) :: fmt

write (fmt,&apos(A,I0,A)&apos) &apos(&apos,n,&apos(2x,f8.2))&apos
write (30,fmt) array

where "n" is the number of elements in the array.

Another option is to use an extension called Variable Format Expressions (VFEs).  This was created by DEC in the 1970s and it earned the enmity of Fortran compiler writers everywhere who were pestered by their customers to support it as well.  With VFEs, you can enclose an integer expression in angle brackets and the value of the expression will be used in the format.  For example:

<![CDATA[write (30, '((2x,f8.2)') array]]>

Intel Fortran, of course, given its DEC heritage, supports VFEs, but I don't recommend their use if you have other reasonable options.

Look to the future

Fortran 2008 solves this problem with a feature called the "unlimited format item" where a * can be used as a group repeat count.  Its effect is "as if its enclosed list were preceded by a very large repeat count".  For example:

'(*(2x,f8.2))'

This lets you avoid having to write a specific large number as the repeat count and makes it more obvious what is going on.  Intel Fortran does not support this yet.

The Doctor's advice, should you find yourself in this situation, is to use the large repeat count, at least until the compiler you use supports the unlimited format item.  You may find some cases where VFEs simplify your coding, so feel free to use them if there is no reasonable standard-conforming alternative.

Got suggestions for future Doctor Fortran columns?  Let me know!

URL: http://feedproxy.google.com/~r/IntelSoftwareNetworkBlog/~3/ZNYZ-FpNvyY/

:, , , , , , , ,

Leave a Reply

Powered by WP Hashcash

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...