My codes are written below:
DIMENSION T(10)
DATA A,B /9.,5./
IS=1
J=J+3
T(j-2)=A
T(J-1)=A-B
80 T(J)=T(1)+T(J-1)
J=J+1
IF(J.NE.10) GOTO 80
DO I=1,5
WRITE (*,15) I, T(J)
END DO
15 FORMAT ('T('I2')=', F8.4)
STOP
END
My compiling error is written below:
jdoodle.f95:13:16:
15 FORMAT ('T('IS')=', F8.4)
1
Error: GNU Extension: Missing comma at (1)
jdoodle.f95:11:20:
WRITE (*,15) I, T(J)
1
Error: FORMAT label 15 at (1) not defined
Could you please tell me where is the false statement of my Fortran code? The result must be T(1)=nnn.0nnn I think.
As can be seen, replacing the format specification with
15 FORMAT ('T(',I2,')=',F8.4)
stops the compiler complaining. I'll answer more generally now.
A format specification can be made up of multiple format items where each item is an edit descriptor or (recursively) a parenthesized list of format items.
It is usually necessary to separate each format item with a comma. In the format of the question the edit descriptors are 'T(', I2 and ')='. [The first and last are character string edit descriptors and the second is a data edit descriptor.] Neither comma between the two pairs is allowed to be omitted.
From the Fortran 2008 standard, the comma is allowed to be omitted only in the following cases:
between a P edit descriptor and an immediately following F, E, EN, ES, D, or G edit descriptor, possibly preceded by a repeat specification;
before a slash edit descriptor when the optional repeat specification does not appear;
after a slash edit descriptor;
before or after a colon edit descriptor.
Of course, just because such commas may be omitted that doesn't mean that they should be. Having an optional comma present never hurts.
Further, as suggested by the compiler's message, a compiler may choose to accept the absence of commas even when a compliant program must have them (although the compiler must be able to detect such non-compliance). As a personal statement I'd suggest avoiding such non-standard writing.
As has been noted in comments, even with the corrected format specification, the program is still not valid: having j=j+3 before j is first defined is not allowed.
Thank you very much, I've just found a solution!
The code is:
DIMENSION T(10)
DATA A,B /9.,5./
IS=1
J=J+3
T(J-2)=A
T(J-1)=A-B
80 T(J)=T(1)+T(J-1)
J=J+1
IF(J.NE.10) GOTO 80
DO I=1,5
WRITE (*,15) I, T(I)
END DO
15 FORMAT ('T(',I2,')=',F8.4)
STOP
END
The result is:
T( 1)= 9.0000
T( 2)= 4.0000
T( 3)= 13.0000
T( 4)= 22.0000
T( 5)= 31.0000
Thank you.
Related
As shown in the following code that I use to practice fixed-form Fortran (because the code I am trying to learn is fixed form Fortran), the 4th format statement and the reading from file 1 are newly added. The code worked as expected prior to adding these statements, but now the intel ifort compiler with no additional flags will not compile the 4th format statement and returns the following error:
fortPractice.for(18): error #5082: Syntax error, found FORMAT_ELEMENT 'format' when expecting one of: <END-OF-STATEMENT> ;
4 format(i6,2x)
--------------^
fortPractice.for(26): error #6052: This label has not been defined as a FORMAT label.
write(2,3)
----------------------------------^
The code is:
c This is a script for practicing Fortran codes
program fortPractice
implicit none
integer :: x(0:5),y(2:7)
integer :: nph(1:6)
real :: z(4:9)
integer :: i
OPEN(unit=1,file='test.txt',status='old')
read(1,*) nph
close(unit=1)
open(unit = 2, file = 'output.txt')
2 format(i3,2x,i3,2x,2e11.2)
3 format(1x,78('*'))
4 format(i6,2x)
do i = 0,5
x(i) = i;
y(i+2) = i+2;
z(i+4) = x(i)**2 + y(i+2)**2
z(i+4) = sqrt(z(i+4)) + 10000
write(2,2) x(i),y(i+2),z(i+4)
write(2,3)
enddo
write(2,*) nph
close(unit = 2)
endprogram fortPractice
Output is a file created by the program. test.txt contains just a row of numbers: 1 2 3 4 5 6
When I comment or remove the 4th format statement then the code compiles and runs as expected. As I am just learning how fixed form Fortran works, I am just interested in why the 4th format statement won't compile.
Edit:
I have replaced all the tabs with spaces, and the program with some more modification shown below can now compile, but the program does not produce the output file, likely encountered some run-time error:
Edit 2:
Nevermind, I forgot to change the file identifiers.
Thanks everyone!
Now we have enough information to solve the problem. In the troublesome source line, the label 4 is preceded by a tab. Tabs in Fortran source are not standard, but Intel Fortran (and many other compilers) support something called "tab source form". The way it works in ifort is as follows:
If the line starts with a tab and then a nonzero digit, the digit is treated as if it were in column 6
If the line starts with a tab and then some other character, then the character is treated as if it were in column 7
If the line starts with a numeric statement label and then a tab, the next character is treated as if it were in column 7
Otherwise, a tab is treated as a blank (this last varies among compilers)
In your case, a tab preceded the 4 so it was taken to be a continuation of the previous line, resulting in an error. Either don't use tabs, or understand how the compiler treats them. Editors that automatically insert tabs will just give you trouble.
I am trying to read the integers in this line:
# 14 14 10
in Fortran 2008.
I attempted to use this code:
read(21, "(A, I,I,I)") garbage, a, b, c
but this is not standard conforming. Intel Fortran issues a warning "Fortran 2008 does not allow this edit descriptor. [I]" and other qeustions explain this problem: Nonnegative width required in format string Error: Nonnegative width required in format string at (1)
How do I properly read the integers of unknown width using Fortran 2008? I can not simply specify I2, because I do not know the width of the integer in advance.
As I hinted in the comments you can read items like this easily with the list directed I/O. The compiler then itself identifies which characters belong to each item in the input list and parse them. The items can be separated by spaces, commas or also a newline.
read(21,*) garbage, a, b, c
This is the most common way to read stuff interactively, but is also useful for parsing lists in data files (CSV and similar).
If on of the numbers were not present in the input record (line in a text file), the reading would continue on the next record.
Suppose I'm trying to write out a CSV file header that looks like this:
STRING1 2001, 2002, 2003, 2004,
And some variable-format Fortran90 code that does this is
INTEGER X<Y
X=2001
Y=2004
WRITE(6,'(A,(999(5X,I4,",")))') ' STRING1',(y,y=X,Y)
The "999" repeats the (5X,I4,",") format structure as many times as it needs to (up to 999 times, at least) to complete. Assume X and Y are subject to change and therefore the number of loop iterations may also change.
But if I want the header to look like this, with an additional string on the end of the sequence, like
STRING1 2001, 2002, 2003, 2004, STRING2
...I have tried adding another A toward the end of the format string, but that repeated variable format structure apparently doesn't know that it needs to "escape" when the integers are done with and so it errors out.
I can work around this by including 'ADVANCE="no"' in the format string and printing the second string using a new WRITE statement to get what I fundamentally want, but is there a way I can do this all with a single format structure?
[NOTE: no angle-bracket answers please; this is for GNU gfortran, which doesn't support that extension]
C'mon folks, get with the program!
This is standard Fortran 2008:
WRITE(6,'(A,*(5X,G0,:,","))') ' STRING1',(y,y=X,Y), ' STRING2'
I am fairly sure that gfortran supports the "indefinite group repeat count". G format was extended in Fortran 2008 to support any intrinsic data type, and a width of zero means "minimum number of characters." The colon is a F77 feature that stops the trailing comma from being emitted.
With this, ifort gives me:
STRING1 2001, 2002, 2003, 2004, STRING2
FWIW, I am not happy with your reuse of y as the loop control variable, since this is NOT a statement entity and will get set to 2005 at the end of the loop. Use a separate variable, please!
program test
character(len=20) :: N_number
integer :: X,Y
X=2001
Y=2004
write(N_number,*) Y-X+1
write(6,'(A,('//TRIM(N_number)//'(5X,I4,","))A)') ' STRING1',(y,y=X,Y),' STRING2'
end program test
It's a shame that the variable-format extension isn't standard. Since it isn't, most people recommend the approach shown by #anonymous. That is, instead of using <N>, you first convert the integer into a string using an internal-write statement. This string representation of N is then inserted within the format expression to be used in the write or print statements.1
Alternatively, you could convert the numerical values from the array into a string.2 It's also pretty straightforward. In the example below, I've shown both of these approaches.
program writeheader
implicit none
character(len=80) :: string1, string2, string3, fmt, num
integer, dimension(10) :: array
integer :: x,y,len
continue
string1 = "begin"
string3 = "end"
array = [1:10]
x = 3
y = 7
!! Method 1: Convert the variable number of values into a string, then use it
!! to create the format expression needed to write the line.
write(num, "(i)") y - x + 1
fmt = "(a,', ',(" // trim(adjustl(num)) // "(i0:', ')), a)"
print fmt, trim(string1), array(x:y), trim(string3)
!! Method 2: Convert the desired range of array values into a character string.
!! Then concat, and write the entire line as a string.
write(string2, "(*(', ',i0))" ) array(x:y)
len = len_trim(string2) + 1
print "(a)", trim(string1) // string2(1:len) // trim(string3)
end program writeheader
In either case shown in the example, the output looks like: begin, 3, 4, 5, 6, 7, end
1 If I can find it, I'll add a link to a nice solution here on SO that created a function to generate the format expression.
2 I've used the array bounds directly here, as an alternative to implied do-loops.
300 do i=1,counter
open(1,file='Pcow_pd.txt')
write(1,*),Sw_pd(i), Pcow_pd(i)
open(2,file='Krw_pd.txt')
write(2,*),Sw_pd(i), Krw_pd(i)
open(3,file='Kro_pd.txt')
write(3,*),Sw_pd(i), Kro_pd(i)
print*, counter
end do
print *,"filled =",filled
When I compile the code I get an error message at write lines which I cannot fix
Compile error: error 573 - Missing expression
As has been commented, there should be no comma before the list of items for output. You should simply have
write(1,*) Sw_pd(i), Pcow_pd(i)
and so on.
The later line
print*, counter
where the comma before counter is absolutely necessary, may add a little confusion on writing. This is perhaps increased by how read is used: there are two forms:
read *, x
read (*,*) y
The first example without an explicit statement of unit implies the same unit as the * in the second and it requires a comma. The second must not have a comma.
A simple way to remember whether the output list has a comma first: if the format comes in isolation use the comma; if the unit is specified, don't.
I am writing some simple output in fortran, but I want whitespace delimiters. If use the following statement, however:
format(A20,ES18.8,A12,ES18.8)
I get output like this:
p001t0000 3.49141273E+01obsgp_oden 1.00000000E+00
I would prefer this:
p001t0000 3.49141273E+01 obsgp_oden 1.00000000E+00
I tried using negative values for width (like in Python) but no dice. So, is there a way to left-justify the numbers?
Many thanks in advance!
There's not a particularly beautiful way. However, using an internal WRITE statement to convert the number to a text string (formerly done with an ENCODE statement), and then manipulating the text may do what you need.
Quoting http://rsusu1.rnd.runnet.ru/develop/fortran/prof77/node168.html
An internal file WRITE is typically
used to convert a numerical value to a
character string by using a suitable
format specification, for example:
CHARACTER*8 CVAL
RVALUE = 98.6
WRITE(CVAL, '(SP, F7.2)') RVALUE
The WRITE statement will fill the
character variable CVAL with the
characters ' +98.60 ' (note that there
is one blank at each end of the
number, the first because the number
is right-justified in the field of 7
characters, the second because the
record is padded out to the declared
length of 8 characters).
Once a number has been turned into a
character-string it can be processed
further in the various ways described
in section 7. This makes it possible,
for example, to write numbers
left-justified in a field, ...
This is easier with Fortran 95, but still not trivial. Write the number or other item to a string with a write statement (as in the first answer). Then use the Fortran 95 intrinsic "ADJUSTL" to left adjust the non-blank characters of the string.
And really un-elegant is my method (I program like a cave woman), after writing the simple Fortran write format (which is not LJ), I use a combination of Excel (csv) and ultraedit to remove the spaces effectively getting the desired LJ followed directly by commas (which I need for my specific import format to another software). BF
If what you really want is whitespace between output fields rather than left-justified numbers to leave whitespace you could simply use the X edit descriptor. For example
format(A20,4X,ES18.8,4X,A12,4X,ES18.8)
will insert 4 spaces between each field and the next. Note that the standard requires 1X for one space, some of the current compilers accept the non-standard X too.
!for left-justified float with 1 decimal.. the number to the right of the decimal is how many decimals are required. Write rounds to the desired decimal space automatically, rather than truncating.
write(*, ['(f0.1)']) RValue !or
write(*, '(f0.1)') RValue
!for left-justified integers..
write(*, ['(i0)']) intValue !or
write(*, '(i0)') RValue
*after feedback from Vladimir, retesting proved the command works with or without the array brackets