I think I still don't understand unformatted IO in Fortran...
I wrote a program that writes the values of a complex array (vz) into a file. The file is opened for writing with unformatted and sequential attributes:
open(unit= 100, file= 'file', form= 'unformatted')
write(100) vz
In another run of the program, on the same platform, I want to read that data into an array, without knowing beforehand the number of data records written in the file.
I open the file again with:
open(unit= 100, file= 'file', form= 'unformatted')
Say I have a total of 100 complex numbers written in the file. If I allocate an array vz with 100 or less elements, say
allocate(vz(10))
and then read the data with either
read(100)vz
or
read(100) (vz(i), i= 1, 10)
the data seems to be read correctly.
However, if I want to read the data and at the same time count the number of complex records, say with:
integer :: i, npts
complex :: z
complex, dimension(:), allocatable :: vz
npts= 0
do
read(100, iostat= i)z
if(i < 0)exit
vz= [ vz, z ] ; npts= npts + 1
end do
I get an error after the first record is read. Using inquire, the value of POSITION after the first record read is 'UNDEFINED' with the Intel compiler and 'APPEND' with gfortran.
Does it mean that for an unformatted read, the input list is read only once, or am I doing some stupid blunder here?
Is there any other solution more elegant?
..
npts= 0
do
read(100, iostat= i)z
if(i < 0)exit
vz= [ vz, z ] ; npts= npts + 1
end do
I get an error after the first record is read. Using inquire, the value of POSITION after the first record read is 'UNDEFINED' with the Intel compiler and 'APPEND' with gfortran.
..
I think I still don't understand unformatted IO in Fortran...
I wrote a program that writes the values of a complex array (vz)
into a file. The file is opened for writing with unformatted and
sequential attributes:
open(unit= 100, file= 'file', form= 'unformatted')
write(100) vz
In another run of the program, on the same platform, I want
to read that data into an array, without knowing beforehand the
number of data records written in the file.
I open the file again with:
open(unit= 100, file= 'file', form= 'unformatted')
Say I have a total of 100 complex numbers written in the file.
If I allocate an array vz with 100 or less elements, say
allocate(vz(10))
and then read the data with either
read(100)vz
or
read(100) (vz(i), i= 1, 10)
the data seems to be read correctly.
However, if I want to read the data and at the same time count the number of complex records, say with:
integer :: i, npts
complex :: z
complex, dimension(:), allocatable :: vz
npts= 0
do
read(100, iostat= i)z
if(i < 0)exit
vz= [ vz, z ] ; npts= npts + 1
end do
I get an error after the first record is read.
On Wednesday, February 23, 2022 at 5:05:09 PM UTC-5, rgae...@gmail.com wrote:.
..
npts= 0
do
read(100, iostat= i)z
if(i < 0)exit
vz= [ vz, z ] ; npts= npts + 1
end do
I get an error after the first record is read. Using inquire, the value of POSITION after the first record read is 'UNDEFINED' with the Intel compiler and 'APPEND' with gfortran.
..
Look into REWIND option in the language standard.
Note READ instruction in your case above causes an IO transfer to the end of record. Subsequent READ is thus positioned wrongly..
On Thursday, February 24, 2022 at 4:49:01 PM UTC+11, FortranFan wrote:Thanks for all replies. They confirm that the program writes the whole array as a continuous stream of bits, with the single addition of the EOF record.
On Wednesday, February 23, 2022 at 5:05:09 PM UTC-5, rgae...@gmail.com wrote:
..
npts= 0
do
read(100, iostat= i)z
if(i < 0)exit
vz= [ vz, z ] ; npts= npts + 1
end do
I get an error after the first record is read. Using inquire, the value of POSITION after the first record read is 'UNDEFINED' with the Intel compiler and 'APPEND' with gfortran.
..
Look into REWIND option in the language standard..
That's irrelevant.
.
Note READ instruction in your case above causes an IO transfer to the end of record. Subsequent READ is thus positioned wrongly..
That's irrelevant. The program is in error to read the individual elements. See earlier postings.
Thanks for all replies. They confirm that the program writes the whole array as a continuous stream of bits, with the single addition of the EOF record.
I consider the question as solved.
That is an inaccurate description and it can actually lead to further confusion, as there is a form of I/O that does produce a stream of bytes. You should understand that unformatted I/O uses logical records. After the last record, no information isleft in the file, definitely not an EOF record. In fact the implementation of unformatted I/O should not be relied upon. It could be anything.
Instead: simply consider such files to be built up from _logical_ records that have to be read one at a time. You can read the whole record or just a small part, but the READ statement will cause the file pointer to move to the next record. You cannotinquire the length of the record, that is information that has to come from somewhere else.
Regards,
Arjen
Well, that may be so, but I can (and did) INQUIRE the
size of the file and in all the tests I did, the result of file_size/file_storage_size (file_storage_size = 8) is equal to
the actual number of complex (single precision) records written
in binary form into the file PLUS one chunk of 8 bits.
If I allocate the array with the correct number of complex elements and read the whole array with
read(unit)vz
the data is read correctly. So, that additional chunk of 8
bits must sit at the very end of the record. If this is not a
EOF record, I don't know what it is.
Well, that may be so, but I can (and did) INQUIRE the size of the file and in all the tests I did, the result of file_size/file_storage_size (file_storage_size = 8) is equal to the actual number of complex (single precision) records written in binaryform into the file PLUS one chunk of 8 bits.
If I allocate the array with the correct number of complex elements and read the whole array with
read(unit)vz
the data is read correctly. So, that additional chunk of 8 bits must sit at the very end of the record.
If this is not a EOF record, I don't know what it is.
8 bits or bytes?
You're correct, you do not know what it is.Indeed, I did not pay due attention to your previous explanation or to the manual, and so misinterpreted the results from my tests.
gfortran's unformatted file format (which I posted upthread) consists,
on a physical level, of sequnces of
- one four-byte record marker containing the length of the data to
follow
- the data
- one four-byte record marker containing the length of the record (same
as the first one), used for BACKSPACE
End of file is simply detected by the end-of-file condition from the operating system.
On a logical level (as seen by the application program), the
bytes in the file system are intereted as records, including an
ENDFILE record.
Note: this is not the only possible scheme - I have seen several others over the years. And the scheme we are considering now is actually more complicated: records longer than 2 or 4 GB require a different approach!
If I understood correctly this time, by writing the whole array with write(unit)vz
the total record is composed by 3 subrecords:
1. the leading record marker, a 4 bytes integer with the number of bytes of the actual data
2. the values of the data in binary form
3. the trailing record marker, another integer of 4 bytes with the same value of the leading.
Correct?
If I write the array using an implied-do loop:
write(unit) (vz(i)= 1, n)
the record will contain the same 3 subrecords, or will be composed by several subrecords?
On Saturday, February 26, 2022 at 6:17:07 AM UTC+11, rgae...@gmail.com wrote:.
If I understood correctly this time, by writing the whole array with write(unit)vzYes, Fortran "unformatted" files consist of RECORDS. Each record is as you describe (up to records of 2^31 bytes).
the total record is composed by 3 subrecords:
1. the leading record marker, a 4 bytes integer with the number of bytes of the actual data
2. the values of the data in binary form
3. the trailing record marker, another integer of 4 bytes with the same value of the leading.
Correct?
The important distinction is they are records, dressed in 3 components : record size header / data / record size trailer.
Most compilers have the record size header as size in bytes as a 4-byte integer, but not all. The header is not defined.
Fortran unformatted binary files are NOT portable between compilers or operating systems.
(This is worse than the case of formatted text files between Dos / unix / linux OS)
It can be very disappointing to find some compilers are different, which I regard as a failing of the standard.
Just look at the myriad of data portability approaches that have been developed because of this failing of the many Fortran Standards to address data portability.
Imagine if the standardised Fortran unformatted file format included some identification of the intrinsic data types in the header/footer.
Unfortunately Fortran unformatted-files are just temporary files.
Note:.
gFortran and iFort use a 4-byte header/footer to indicate the record size, (but what is size?)
For large records, larger than 2^31 bytes, gFortran adopts "sub records" of smaller than 2^31 - 9 bytes(?) with special -ve record size header values.
iFort might use a different approach for larger records and might use words instead of bytes for size.
Silverfrost FTN95 uses a 1-byte header/footer for records smaller than 256 bytes, then a 5-byte header/footer for larger records.
If only there was an adopted standard, unformatted files might be more portable !!
If I write the array using an implied-do loop:
write(unit) (vz(i)= 1, n)
the record will contain the same 3 subrecords, or will be composed by several subrecords?
Yes, this would be the same, if "n" was the dimension of vz. There is 1 record.
Your earlier example is different.
complex :: z
do
read(100, iostat= i)z
if(i < 0)exit
end do
In this case, each read is reading the next record. It could read the first 8 bytes of the data in the record, then step to the next logical record.
Both "fixed length record direct access" files and "stream I/O" files do not dress the data in record header/footer.
As such these are more portable, although can vary due to endian format.
I use "fixed length record direct access" files for transferring data between codes that are compiled with different compilers,
mainly for integer and real arrays.
I have no experience of how this record dressing could apply to derived type data structures.
I will write out the intrinsic type components as individual elements of an I/O list or in seperate write statement records.
This approach provides clarity to the structure of the records being written.
On Saturday, February 26, 2022 at 6:17:07 AM UTC+11, rgae...@gmail.com wrote:
If I understood correctly this time, by writing the whole array with
write(unit)vz
the total record is composed by 3 subrecords:
1. the leading record marker, a 4 bytes integer with the number of bytes of the actual data
2. the values of the data in binary form
3. the trailing record marker, another integer of 4 bytes with the same value of the leading.
Correct?
Yes, Fortran "unformatted" files consist of RECORDS. Each record
is as you describe (up to records of 2^31 bytes).
The important distinction is they are records, dressed in 3
components : record size header / data / record size trailer.
Most compilers have the record size header as size in bytes as
a 4-byte integer, but not all.
The header is not defined.
Fortran unformatted binary files are NOT portable between compilers or operating systems.
(This is worse than the case of formatted text files between Dos /
unix / linux OS)
It can be very disappointing to find some compilers are different, which I regard as a failing of the standard.
Just look at the myriad of data portability approaches that have been developed because of this failing of the many Fortran Standards to address data portability.
Imagine if the standardised Fortran unformatted file format included some identification of the intrinsic data types in the header/footer.
Unfortunately Fortran unformatted-files are just temporary files.
Note:
gFortran and iFort use a 4-byte header/footer to indicate the
record size, (but what is size?)
For large records, larger than 2^31 bytes, gFortran adopts "sub
records" of smaller than 2^31 - 9 bytes(?) with special -ve record
size header values.
iFort might use a different approach for larger records and might use words instead of bytes for size.
Silverfrost FTN95 uses a 1-byte header/footer for records smaller
than 256 bytes, then a 5-byte header/footer for larger records.
If only there was an adopted standard, unformatted files might
be more portable !!
Fortran unformatted binary files are NOT portable between compilers or operating systems.
(This is worse than the case of formatted text files between Dos / unix / linux OS)
It can be very disappointing to find some compilers are different, which I regard as a failing of the standard.
Just look at the myriad of data portability approaches that have been developed
because of this failing of the many Fortran Standards to address data portability.
Imagine if the standardised Fortran unformatted file format included some identification of the intrinsic data types in the header/footer. Unfortunately Fortran unformatted-files are just temporary files.
What you are trying to do might be done better with an unformatted
stream, which has no records (like a binary file in C).
You can look at
https://www.programming-idioms.org/idiom/228/copy-a-file
(click on the Fortran tab) for an example on how to manipulate
unformatted files, although what that example does is a bit
different from what you want. It might give you a first
idea, though.
If you want to allocate before the read, you can write the length on
a separate record.
READ(5,*) N
ALLOCATE (X(N),Y(N))
READ(5,*) (X(I), I=1,N),(Y(I), I=1,N)
and that works about as well for UNFORMATTED, and STREAM or not.
For some file formats, you can write all the lengths out at first,
and then all the data using lengths:
READ(5,*) L, M, N
READ(5,*) (X(I), I=1,L),(Y(I), I=1,M),(Z(I),I=1,N)
or almost any other combination of reading that you like.
One that you can't do, that I tried in Fortran-77 days, and even
had the form to report bugs to DEC:
READ(5,*,END=10) (X(I),Y(I),I=1,M)
I=M+1
10 N=I-1
The standard does not make any guarantees about the
data read in, in the case that END= is taken.
On 3/3/22 6:08 PM, gah4 wrote:
If you want to allocate before the read, you can write the length on
a separate record.
READ(5,*) NThese days one would simply use
ALLOCATE (X(N),Y(N))
READ(5,*) (X(I), I=1,N),(Y(I), I=1,N)
read(5,*) x, y
or
read(5,*) x(1:n), y(1:n)
and that works about as well for UNFORMATTED, and STREAM or not.
For some file formats, you can write all the lengths out at first,
and then all the data using lengths:
READ(5,*) L, M, NSame here
READ(5,*) (X(I), I=1,L),(Y(I), I=1,M),(Z(I),I=1,N)
read(5,*) x(1:L), y(1:M), z(1:N)
or something similar.
or almost any other combination of reading that you like.
One that you can't do, that I tried in Fortran-77 days, and even
had the form to report bugs to DEC:
READ(5,*,END=10) (X(I),Y(I),I=1,M)
I=M+1
10 N=I-1
The standard does not make any guarantees about the
data read in, in the case that END= is taken.
This is because some systems buffer the records, and if a hardware eof
is encountered, then the status of the arrays and of the implied do
variable might be in some undefined state. The i/o library might have
been trying to read the blocks in reverse order, for example, or with cylinder reads on a hard disk which would fill in the arrays with gaps.
So the standard just punted and said that nothing is defined in order to
give the i/o library the maximum flexibility.
On Thursday, March 3, 2022 at 10:40:00 PM UTC-8, Ron Shepard wrote:.
On 3/3/22 6:08 PM, gah4 wrote:
If you want to allocate before the read, you can write the length on
a separate record.
READ(5,*) NThese days one would simply use
ALLOCATE (X(N),Y(N))
READ(5,*) (X(I), I=1,N),(Y(I), I=1,N)
read(5,*) x, yOnly if you are reading the whole array, but yes in this case.
I had previously written it without the allocate, as the arrays
could already be big enough.
or
read(5,*) x(1:n), y(1:n)Does this work exactly the same? I suppose so.
I was too used to doing this back to Fortran 66 days.
and that works about as well for UNFORMATTED, and STREAM or not.
For some file formats, you can write all the lengths out at first,
and then all the data using lengths:
READ(5,*) L, M, NSame here
READ(5,*) (X(I), I=1,L),(Y(I), I=1,M),(Z(I),I=1,N)
read(5,*) x(1:L), y(1:M), z(1:N)
or something similar.One that I thought of, but never did, in the olden days:
or almost any other combination of reading that you like.
READ(5,*) L, (X(MIN(I,L)),I=1,L)
which avoids going outside the array,
if the L read in is
larger than expected. Not so easy to write that the other way.
On Wednesday, February 23, 2022 at 11:49:46 PM UTC-8, Thomas Koenig wrote:
(snip)
What you are trying to do might be done better with an unformatted
stream, which has no records (like a binary file in C).
You can look at
https://www.programming-idioms.org/idiom/228/copy-a-file
(click on the Fortran tab) for an example on how to manipulateNote that with UNFORMATTED (or, for that matter, FORMATTED),
unformatted files, although what that example does is a bit
different from what you want. It might give you a first
idea, though.
and STREAM or not, the program reading the data in needs to know how
long it is. In some cases, that is always known, but it most it is best to write the length into the file.
As I noted above, and it should work for any type of Fortran I/O,
you can read the length and data in the same statement:
READ(5,*) N,(X(I), I=1,N),(Y(I), I=1,N)
In Fortran 66 and 77 days, before dynamic allocation, that was fine.
If you want to allocate before the read, you can write the length on
a separate record.
READ(5,*) N
ALLOCATE (X(N),Y(N))
READ(5,*) (X(I), I=1,N),(Y(I), I=1,N)
and that works about as well for UNFORMATTED, and STREAM or not.
For some file formats, you can write all the lengths out at first,
and then all the data using lengths:
READ(5,*) L, M, N
READ(5,*) (X(I), I=1,L),(Y(I), I=1,M),(Z(I),I=1,N)
or almost any other combination of reading that you like.
One that you can't do, that I tried in Fortran-77 days, and even
had the form to report bugs to DEC:
READ(5,*,END=10) (X(I),Y(I),I=1,M)
I=M+1
10 N=I-1
The standard does not make any guarantees about the
data read in, in the case that END= is taken.
One that I thought of, but never did, in the olden days:
READ(5,*) L, (X(MIN(I,L)),I=1,L)
which avoids going outside the array, if the L read in is
larger than expected. Not so easy to write that the other way.
On 3/4/22 3:09 AM, gah4 wrote:.
One that I thought of, but never did, in the olden days:
READ(5,*) L, (X(MIN(I,L)),I=1,L)
which avoids going outside the array, if the L read in isBy "outside" the array, I'm assuming you mean negative values of L.
larger than expected. Not so easy to write that the other way.
However, the implied do loop itself prevents those array elements from.
being accessed, so I do not think the min(I,L) expression actually does anything in that i/o list. If it were min(I,M) where M was the declared
array upper bound, then yes, it would prevent accesses outside the array while still processing the correct number of elements during the data transfer.
One can also skip over data within a record.
READ(5,*) L, X(1:L), M, (IDUM,i=1,M), N
This reads the indicated X(1:L) elements, then it reads M the number of elements to skip over, and then it gets the correct N value from the
correct position within the input record. Like magic. I have also seen
this written as
READ(5,*) L, X(1:L), N, (N,i=1,N), N
or as
READ(5,*) L, X(1:L), N, (N,i=1,N+1)
which is much more obscure, but accomplishes the same thing. As far as I know, that is legal and the operations are well defined, but it does
cause some head scratching the first time you see it to figure out which
N is changing and which N is not within that implied do loop.
I also think that the array slice notation works for i/o the same as the implied do loop. Consider the following:
implicit none
integer :: n, a(3)
a = -1
read(*,*) n, a(1:n)
write(*,*) n, a
end
Here, the (1:n) that is active during the read statement is the n that
was just read. If n is <=0, then nothing is transferred, and if n>3,
then elements that are out of bounds are accessed, generating a runtime
i/o error.
That is the same thing that happens with the equivalent
implied do loop expression. However, I don't know how to skip over data
in the input record with array slice notation, I think you must use the implied do loop for that.
Such i/o statements can result in very complicated logic. Consider an
i/o list like
n, a(1:n), m, b(n:m)
That is legal and works just like you would expect it to work. That is,
the number of elements that are transferred and where they go depend on
the values that are read within that data transfer. In most other
languages, the programmer would need manually buffer the data during the
i/o statement, and then transfer that information into a(:) and b(:) afterwards, or execute the parts of the statement separately with a
series of i/o operations.
On 3/4/22 3:09 AM, gah4 wrote:
One that I thought of, but never did, in the olden days:
READ(5,*) L, (X(MIN(I,L)),I=1,L)
which avoids going outside the array, if the L read in is
larger than expected. Not so easy to write that the other way.
By "outside" the array, I'm assuming you mean negative values of L.
However, the implied do loop itself prevents those array elements from
being accessed, so I do not think the min(I,L) expression actually does anything in that i/o list. If it were min(I,M) where M was the declared
array upper bound, then yes, it would prevent accesses outside the array while still processing the correct number of elements during the data transfer.
Also, Fortran 66 doesn't allow DO or implied DO loops for 0 items.
On 3/5/2022 12:57 AM, gah4 wrote:
Also, Fortran 66 doesn't allow DO or implied DO loops for 0 items.The wording of FORTRAN 66 is:
"The control variable is assigned the value represented by the initial parameter. This value must be less than or equal to the value
represented by the terminal parameter."
In other words, if the loop would execute zero times, the program is non-conformant to the standard. Practically speaking, F66 compilers
didn't bother checking this, so the behavior ended up being 1-trip and
most programmers assumed that's how the language defined it.
F77 does have zero-trip DO loops, but not for data-implied-DO.
On Saturday, March 5, 2022 at 9:40:29 AM UTC-8, Steve Lionel wrote:.
On 3/5/2022 12:57 AM, gah4 wrote:
Also, Fortran 66 doesn't allow DO or implied DO loops for 0 items.The wording of FORTRAN 66 is:
"The control variable is assigned the value represented by the initial parameter. This value must be less than or equal to the value
represented by the terminal parameter."
In other words, if the loop would execute zero times, the program is non-conformant to the standard. Practically speaking, F66 compilersIBM compilers would check it for constants, but not variables.
didn't bother checking this, so the behavior ended up being 1-trip and
most programmers assumed that's how the language defined it.
Also, the constants had to be greater than zero.
I never tried setting a variable right before the DO statement,
where an optimizing compiler might figure it out.
F77 does have zero-trip DO loops, but not for data-implied-DO.This would be io-implied-do.
Also, for those who forgot by now, Fortran 66 doesn't allow constants.
in I/O lists.
I had variables with names like ZERO and ONE, to write those
values out. One of my favorite new features in Fortran 77 was expressions
in I/O lists.
On Sunday, March 6, 2022 at 5:35:32 AM UTC+11, gah4 wrote:[...]
On Saturday, March 5, 2022 at 9:40:29 AM UTC-8, Steve Lionel wrote:
.F77 does have zero-trip DO loops, but not for data-implied-DO.This would be io-implied-do.
No, it is an implied-DO.
.
An implied-DO can exist only in an I/O list.
.
Also, for those who forgot by now, Fortran 66 doesn't allow constants
in I/O lists.
I had variables with names like ZERO and ONE, to write those
values out. One of my favorite new features in Fortran 77 was expressions
in I/O lists.
.
Expressions in I/O lists had been already available in PL/I for more than
a decade.
An implied-DO can exist only in an I/O list.
R840 data-implied-do is ( data-i-do-object-list , [ integer-type-spec :: ] data-i-do-variable =
scalar-int-constant-expr ,
scalar-int-constant-expr
[ , scalar-int-constant-expr ]
R774 ac-implied-do is ( ac-value-list , ac-implied-do-control )
Speaking of parameters in data statements in F77, I remember also that expressions were not allowed. So if ONE was a parameter, then a data statement like
DATA X/-ONE/
was not allowed. That was an expression, not a constant. The programmer
was required to do something like
PARAMETER (MONE=-ONE)
DATA X/MONE/
On 3/6/2022 2:45 AM, Robin Vowels wrote:False.
An implied-DO can exist only in an I/O list.Not so.
.
R840 data-implied-do is ( data-i-do-object-list , [ integer-type-spec :: ] data-i-do-variable =
scalar-int-constant-expr ,
scalar-int-constant-expr
[ , scalar-int-constant-expr ]
8.6.7 DATA statement
and...
R774 ac-implied-do is ( ac-value-list , ac-implied-do-control )
7.8 Construction of array values
--
Steve Lionel
On Monday, March 7, 2022 at 4:43:56 AM UTC+11, Ron Shepard wrote:
As Steve Lionel points out, implied do was also used in data statements
in F66.
No it wasn't. See 7.2.2 of the standard.
F66 did not have parameters, so any such data statements had to
be defined with literal constants, so it was straightforward for the programmer to ensure the loop was executed at least once.
In your imagination.
DATA statements in F66 could not have implied-DO.
But implied do
in an i/o list could have variables, even variables that were defined within the i/o operation itself. F77 introduced parameters, and those parameters could be used in data statements, both as values and as the limits for implied do loops in data statements, so then the possibility
of zero-trip loops was addressed. F90 extended the use of implied do
loops to array constructors.
What?
See 7.1.2.8, which states unequivocally that m1, m2, and m2 can be an "integer constant or integer variable".
On 3/6/22 1:45 AM, Robin Vowels wrote:.
On Sunday, March 6, 2022 at 5:35:32 AM UTC+11, gah4 wrote:[...]
On Saturday, March 5, 2022 at 9:40:29 AM UTC-8, Steve Lionel wrote:
.F77 does have zero-trip DO loops, but not for data-implied-DO.This would be io-implied-do.
No, it is an implied-DO.
.
An implied-DO can exist only in an I/O list.
As Steve Lionel points out, implied do was also used in data statements.
in F66.
F66 did not have parameters, so any such data statements had to.
be defined with literal constants, so it was straightforward for the programmer to ensure the loop was executed at least once.
But implied do.
in an i/o list could have variables, even variables that were defined
within the i/o operation itself. F77 introduced parameters, and those parameters could be used in data statements, both as values and as the
limits for implied do loops in data statements, so then the possibility
of zero-trip loops was addressed. F90 extended the use of implied do
loops to array constructors.
Speaking of parameters in data statements in F77, I remember also that expressions were not allowed. So if ONE was a parameter, then a data statement like
DATA X/-ONE/
was not allowed. That was an expression, not a constant. The programmer
was required to do something like
PARAMETER (MONE=-ONE)
DATA X/MONE/
.
Also, for those who forgot by now, Fortran 66 doesn't allow constants
in I/O lists.
Or in DO loop ranges..
.Along with expressions in DO loops. In F77, there were other reasons toI had variables with names like ZERO and ONE, to write those
values out. One of my favorite new features in Fortran 77 was expressions >> in I/O lists.
use parameters such as ZERO, IZERO, ONE, and IONE, among others, rather
than literal constants, so that programming convention continued on
until the present day. Now in F90+ with the ability to specify the kind
of a literal constant, this use of parameters is less critical.
.
Expressions in I/O lists had been already available in PL/I for more than
a decade.
And along with expressions in DO loops, this was also a common extension.
to F66, which caused portability issues with codes moving between
different vendors. Portability of PL/I codes between different vendors
was obviously less of an issue since many vendors did not even attempt
to support the language, so the issue never arose.
On Sunday, March 6, 2022 at 5:51:15 PM UTC-8, Robin Vowels wrote:.
On Monday, March 7, 2022 at 4:43:56 AM UTC+11, Ron Shepard wrote:(snip)
As Steve Lionel points out, implied do was also used in data statements in F66.No it wasn't. See 7.2.2 of the standard.
F66 did not have parameters, so any such data statements had to
be defined with literal constants, so it was straightforward for the programmer to ensure the loop was executed at least once.
And, if you go back and look, Steve Lionel didn't mention it as being.
in Fortran 66.
data-implied-do has since been added, and so the statement.
that implied-do is only in I/O statements is (currently) false.
.In your imagination.
.DATA statements in F66 could not have implied-DO.(snip)
But implied do
in an i/o list could have variables, even variables that were defined within the i/o operation itself. F77 introduced parameters, and those parameters could be used in data statements, both as values and as the limits for implied do loops in data statements, so then the possibility of zero-trip loops was addressed. F90 extended the use of implied do loops to array constructors.
What?
See 7.1.2.8, which states unequivocally that m1, m2, and m2 can be an "integer constant or integer variable".
They can in I/O statements, but not in DATA statements,.
as DATA statements.
have to be resolved at compile time. Remember, the variables have the SAVE attribute.
And, if you go back and look, Steve Lionel didn't mention it as being
in Fortran 66.
If you go back, you will see that we were talking about F66.
Please try to keep your eye on the ball.
On Monday, March 7, 2022 at 4:43:56 AM UTC+11, Ron Shepard wrote:[...]
In your imagination.
DATA statements in F66 could not have implied-DO.
In your imagination.You are right about this, so I stand corrected. My memory was off. When
DATA statements in F66 could not have implied-DO.
I used these, it must have been either an extension to f66 or perhaps it
was an early f77 compiler. The common use for this was to initialize
subsets of the elements of larger arrays. The different subsets could
appear in separate data statements, keeping the number of continuation
lines manageable. There was also the R* repeat counts in the data lists
that were allowed to shorten the data statements.
I also remember using sometimes extensive equivalence statements in
order to initialize subsets of elements of large arrays in data
statements. Each of the equivalenced arrays could appear in its own data statement.
On Monday, March 7, 2022 at 9:54:16 AM UTC-8, Ron Shepard wrote:
(snip)
In your imagination.You are right about this, so I stand corrected. My memory was off. When
DATA statements in F66 could not have implied-DO.
I used these, it must have been either an extension to f66 or perhaps it
was an early f77 compiler. The common use for this was to initialize
subsets of the elements of larger arrays. The different subsets could
appear in separate data statements, keeping the number of continuation
lines manageable. There was also the R* repeat counts in the data lists
that were allowed to shorten the data statements.
I found out about DATA statements early after I started learning Fortran,
and in one program initialized a large (for the time) array to zero.
Then I decided to punch the object program on cards. The whole array
got punched!
Some object formats compress out zeros, but not all
of them.
And if you initialize a large array to non-zero, it will all go
in to the object program on most other systems.
gah4 <gah4@u.washington.edu> schrieb:
On Monday, March 7, 2022 at 9:54:16 AM UTC-8, Ron Shepard wrote:
(snip)
In your imagination.You are right about this, so I stand corrected. My memory was off. When
DATA statements in F66 could not have implied-DO.
I used these, it must have been either an extension to f66 or perhaps it >>> was an early f77 compiler. The common use for this was to initialize
subsets of the elements of larger arrays. The different subsets could
appear in separate data statements, keeping the number of continuation
lines manageable. There was also the R* repeat counts in the data lists
that were allowed to shorten the data statements.
I found out about DATA statements early after I started learning Fortran,
and in one program initialized a large (for the time) array to zero.
Then I decided to punch the object program on cards. The whole array
got punched!
I can imagine.
I began programming with cards, and it does give you some insight into
the computing process when you compile your source code from cards,
punch object decks onto cards, put them in card boxes, and physically
carry them back and forth to the computer center when you submit your jobs.
When you do this with tapes or disk storage (or these days SSD or cloud storage), it all becomes a little more abstract.
As to whether it is good or bad to put initialized arrays in your codes
or to assign values at run time depends on how many boxes your object
decks are, whether you have to pay to have the cards read every time you
run a job, and the relative costs (in money, time, or general hassle) of reading the cards or executing the loops at run time. I also remember
doing things like taking my cards (both source code and object code) and marking diagonal stripes on the edges with a felt tip marker; just in
case the box was dropped, that made it possible to put everything back
in order. That was an era when person time was cheap and computer time
was expensive.
Looking at ELF, it has the .bss and .data (and .data1) sections.
.bss does not contribute to the file space and is initialized to
zero on program startup (usually done by mapping a zero page these
days) The .data sectoin holds initialized data.
While ELF is quite modern, it took concepts from older object
formats, so what happened when you initialized the array with
all zeros, it got put into .data instead of .bss. (The names
may have been different at the time, although at least the
name BSS dates back to the IBM 704, but the meaning may
have been subtly different).
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 157 |
Nodes: | 16 (0 / 16) |
Uptime: | 16:36:21 |
Calls: | 3,193 |
Files: | 10,512 |
Messages: | 2,978,769 |