I want to load a list from an input file via a namelist. To compile, I use gfortran:
PROGRAM main
IMPLICIT NONE
INTEGER :: val,err
NAMELIST /myNamelist/ val
OPEN(100,file='input.txt')
READ(unit=100,nml=myNamelist,iostat=err)
CLOSE(100)
PRINT *, val
END PROGRAM
The input.txt looks like the following:
&myNamelist
val = 3e3
/
The program prints a 0 instead of 3000. If I plug in val = 3000 in the input file, it works. It seems that gfortran does not support scientific notation in a namelist. With ifort however it runs fine. Is there a workaround or something to use scientific notation in a namelist with gfortran?
You use iostat=err, but you do not check the value of err! If you did that you would found out that an error condition happened and err is nonzero. Therefore, val is of no use.
The scientific notation is not valid for integer input. Either read a real variable or do not use the scientific notation.
Try:
PROGRAM main
IMPLICIT NONE
INTEGER :: val,err
character(256) :: msg
NAMELIST /myNamelist/ val
OPEN(100,file='input.txt')
READ(unit=100,nml=myNamelist,iostat=err,iomsg=msg)
CLOSE(100)
PRINT *, err
PRINT *, msg
print *, val
END PROGRAM
run:
> sunf90 intnml.f90
> ./a.out
1083
unexpected character in integer value
0
BTW, Intel Fortran accepts the value, but that is a non-standard extension. Your program would be non-portable if you relied on that.
The draft of the 2008 standard that I have to hand states, at para 10.11.3.3.6, in the context of reading name lists:
When the next effective item is of type integer, the value in the input
record is interpreted as if an Iw edit descriptor with a suitable
value of w were used.
In this case gfortran is doing no more than the standard requires while the Intel compiler goes a bit further and implements an extension that copes with a non-standard form of an integer value, ie 3e3.
Related
This question already has an answer here:
Variable format
(1 answer)
Closed 2 years ago.
I used to the Intel fortran compiler which supports using the <n> extension like
write(*, '(<n>(2I4))') (i, 2*i, i=1,n)
To illustrate, I give a s1_fprint.f90 subroutine as follows
subroutine fprint(name,bb)
IMPLICIT NONE
character(len=*), intent(in) :: name
real, intent(in) :: bb(:,:)
integer :: column=10
integer i,j,k,m,n
n = size(bb,1)
m = size(bb,2)
write(*,'(1a)')name
do k=0,m/column-1
write(*, '(1x,<column>i16)')(i,i=k*column+1,(k+1)*column)
write(*,'(1i10,<column>f)')(i,(bb(i,j),j=k*column+1,(k+1)*column),i=1,n)
write(*,'(/)')
end do
if(mod(m,column)/=0)then
write(*, '(1x,<m-m/column*column>i16)')(i,i=m/column*column+1,m)
write(*,'(1i10,<m-m/column*column>f)')(i,(bb(i,j),j=m/column*column+1,m),i=1,n)
write(*,'(/)')
endif
end subroutine fprint
Now, I change the Intel fortran compiler to gfortran, then I test (t1_useSur.f90)
above subroutine in gfortran as follows:
program main
implicit none
real :: A(2,3) = reshape([1.2, 2.3, 3.4, 4.5, 5.6, 6.7], [2,3])
call fprint('A',A)
end program main
which should show us something like
A
1 2 3
1 1.2000000 3.4000001 5.5999999
2 2.3000000 4.5000000 6.6999998
However, in gfortran compiler when I run
gfortran t1_useSur.f90 s1_fprint.f90 -o out
./out
there are many errors as
.\s1_fprint.f90:14.17:
write(*, '(1x,<column>i16)')(i,i=k*column+1,(k+1)*column)
1
Error: Unexpected element '<' in format string at (1)
.\s1_fprint.f90:15.19:
write(*,'(1i10,<column>f)')(i,(bb(i,j),j=k*column+1,(k+1)*column),i=1,n)
1
Error: Unexpected element '<' in format string at (1)
.\s1_fprint.f90:19.17:
write(*, '(1x,<m-m/column*column>i16)')(i,i=m/column*column+1,m)
1
Error: Unexpected element '<' in format string at (1)
.\s1_fprint.f90:20.19:
write(*,'(1i10,<m-m/column*column>f)')(i,(bb(i,j),j=m/column*column+1,m),i=
1
Error: Unexpected element '<' in format string at (1)
Since the <n> extension is not supported by gfortran, how can fix these problems?
Near dupe Variable format statement when porting from Intel to GNU gfortran
For the 1-dim cases like (i,i=...) :
If you have (or get) a version of gfortran that supports F08, which browsing https://gcc.gnu.org/onlinedocs/ appears to be around 4.6.4 up, use * as the count like (1x,*i16)
Otherwise, use the old-as-the-hillsF77 trick: since format repetitions or items 'beyond' the data list are ignored, just use a repetition count that is at least as big as the data will ever be (but not more than HUGE(0)) here (1x,10i16) is actually enough but something like (1x,999i16) makes it much more obvious
or if you like extra work, do on-the-fly like the 2-dim case below
For the 2-dim cases like (i,(bb(i,j),j=...),i=...) which currently use format looping to insert record breaks either:
reduce to 1-dim by making the record breaks into separate WRITEs:
do i=...
write(*,'(1i10,*f)') i,(bb(i,j),j=...)
end do !i
generate the correct count on-the-fly:
character(len=20) fmt
...
write(fmt,'(a,i0,a)') '(1i10,', numcols_expression, 'f)'
write(*, trim(fmt)) (i,(bb(i,j),j=...),i=...)
... or ...
write(fmt,'(i0)') numcols_expression
write(*, '(1i10,'//trim(fmt)//'f)') (i,bb(i,j),j=...),i=...)
PS: you don't actually need 1i10 just i10, but I left it for consistency. Also rather than a loop for the full chunks then an if for the partial chunk, which have to be kept in sync, I would probably do:
do k=1,m,column
l=min(k+column-1,m)
... print chunk for i=k,l (numcols is l-k+1) ...
end do !k
I have a data file, some of the numbers are really big, like 1E252. How do I read data into Fortran as 1D252. I've tried declaring the variable as double and kind=16, but when its read in as 1E252, it errors.
Unfortunately, the easy solution, to parse the data file and convert all Es to Ds won't work because it also needs to be compatible with python.
Is there something more elegant than this?
program test
Integer :: i
real (kind = 8) :: another_test
Character(len=20) :: char_arr
char_arr = "1.10E+223"
Do i = 1,20
If (char_arr(i:i) == "E") then
char_arr(i:i) = "D"
EndIf
EndDo
Read(char_arr, *) another_test
Write(*,*) another_test
end program test
This isn't a full answer, mainly because I haven't been able to reproduce your premise. (I'm at my home computer, I only have access to gfortran v7.3.0 on Windows 10/cygwin.)
This code compiled perfectly fine and printed the correct value:
program large_float
use iso_fortran_env, only: real64
implicit none
character(len=20) :: strrep
real(kind=real64) :: val
strrep = '1.10E+223'
read (strrep, *) val
print *, val
end program large_float
Now you can see what I do differently to you is this: Instead of the ambiguous kind=8 I use the intrinsic iso_fortran_env to get the correct kind for 64 bit floating values.
I would strongly recommend to use this syntax, as it is compiler independent1 and you will know exactly what you get.
1iso_fotran_env was added I think in Fortran 2003, but I don't know of any Fortran compiler that doesn't recognise it. If you get an error, you can still use the selected_real_kind:
integer, parameter :: real64 = selected_real_kind(R=300)
Here is the source (lets call it test4.F):
do 10 i=1
write(*,*) i
10 continue
end
With gfortran:
$gfortran test4.F
$./a.out
-259911288
with ifort:
$ifort test4.F
$./a.out
0
I know the syntax is incorrect. So both should throw compile-time errors.
Your test program is indeed not valid Fortran, but there isn't a syntax problem.
When the file has a .F suffix both gfortran and ifort assume that the program uses fixed form source. In fixed form source, blanks in statements aren't significant (outside character contexts). Your program is equivalent to:
do10i=1
write(*,*) i
10 continue
end
With comments:
do10i=1 ! Set the real variable do10i to value 1
write(*,*) i ! Write the undefined integer variable i
10 continue ! Do nothing
end ! End execution
Because of implicit typing you have a defaul real variable do10i and so there isn't a syntax error for a do control, and there isn't a do control that sets i to 1.
Instead your program is invalid because you are referencing the value of i although it hasn't first been defined (because it isn't a loop variable). But this isn't an error the compiler has to complain about at compile time (or even run time). A compiler is allowed to print any value it likes. gfortran chose one, ifort another.
Liberal use of implicit none and avoiding fixed-form source are good ways to avoid many programming errors. In this case, use of an end do instead of continue would also alert the compiler to the fact that you intended there to be some looping.
Which version of gfortran are you using? With gfortran-6, the following
PROGRAM MAIN
USE ISO_FORTRAN_ENV, ONLY:
1 COMPILER_VERSION,
2 COMPILER_OPTIONS
C EXPLICIT TYPING ONLY
IMPLICIT NONE
C VARIABLE DECLARATIONS
INTEGER I
DO 10 I = 1
WRITE (*,*) I
10 CONTINUE
PRINT '(/4A/)',
1 'THIS FILE WAS COMPILED USING ', COMPILER_VERSION(),
2 ' USING THE OPTIONS ', COMPILER_OPTIONS()
END PROGRAM MAIN
indeed throws the error
main.F:13:13:
DO 10 I = 1
1
Error: Symbol ‘do10i’ at (1) has no IMPLICIT type
I suspect that test4.F does not include the implicit none statement. Consequently, DO 10 I = 1 is interpreted as an implicitly defined real variable DO10I = 1. Here is a sample of a fixed form statement showing what are now (post Fortran 90) considered significant blanks followed by an equivalent statement without the blanks
DO I=1 , M AX ITER S
DO I = 1 , MAXITERS
Upshot, always use explicit variable declarations in all your programs. Better yet, only write Fortran in free source form main.f90. Free source form is more compatible with modern interactive input devices than fixed form. The maximum line length is 132 characters, compared to the older limit of 72 characters. This reduces the possibility of text exceeding the limit, which could lead the compiler to misinterpret names. Here's the same code in free source form
program main
use ISO_Fortran_env, only: &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
! Explicit typing only
implicit none
! Variable declarations
integer :: i
do i = 1, 3
write (stdout, *) i
end do
print '(/4a/)', &
' This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
and
gfortran-6 -std=f2008ts -o main.exe main.f90
./main.exe
yields
1
2
3
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -std=f2008ts
I took the following function ran0 from the text Numerical Recipes. I wrote my own program random2 to call ran0.
Why does this code cause a segmentation fault? Thanks for your time.
FUNCTION ran0(idum)
INTEGER idum,IA,IM,IQ,IR,MASK
REAL ran0,AM
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,MASK=123459876)
INTEGER k
idum=ieor(idum,MASK)
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
ran0=AM*idum
idum=ieor(idum,MASK)
return
END FUNCTION
PROGRAM random2
IMPLICIT NONE
REAL :: ran0
PRINT *, ran0(6)
END PROGRAM
You pass the constant 6.0 to your function as the IDUM dummy argument. You then (attempt to) modify this argument with lines such as idum = ieor(...) etc. You are effectively trying to modify a constant.
The value of 6.0 has been fixed for some time now - long enough that most programmers expect to find it somewhere between 5.0 and 7.0. Please don't try and change it.
Extending the answer of IanH, if you partially rewrite this in more modern Fortran:
module my_subs
contains
FUNCTION ran0(idum)
INTEGER, intent(inout) :: idum
INTEGER IA,IM,IQ,IR,MASK
REAL ran0,AM
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,MASK=123459876)
INTEGER k
idum=ieor(idum,MASK)
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
ran0=AM*idum
idum=ieor(idum,MASK)
return
END FUNCTION
end module my_subs
PROGRAM random2
use my_subs
IMPLICIT NONE
!REAL :: ran0
PRINT *, ran0(6)
END PROGRAM
Identifying the argument as being both input and output with the intent(inout) attribute and placing the subroutine in a module and using that module to allow the compiler to check the consistency of the arguments, the compiler is likely to find this problem. For example, gfortran outputs:
PRINT *, ran0(6)
1
Error: Non-variable expression in variable definition context (actual argument to INTENT = OUT/INOUT) at (1)
How can I read and write to the standard input, output and error streams stdin, stdout and stderr in Fortran? I've heard writing to stderr, for example, used to be write(5, fmt=...), with 5 the unit for stderr, and I know the way to write to stdout is to use write(*, fmt=...).
How do I read and write to the standard input and output units with the ifort compiler?
Compiler version:
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 10.0 Build 20070426 Package ID: l_fc_p_10.0.023 Copyright (C) 1985-2007 Intel Corporation. All rights reserved
If you have a Fortran 2003 compiler, the intrinsic module iso_fortran_env defines the variables input_unit, output_unit and error_unit which point to standard in, standard out and standard error respectively.
I tend to use something like
#ifdef f2003
use, intrinsic :: iso_fortran_env, only : stdin=>input_unit, &
stdout=>output_unit, &
stderr=>error_unit
#else
#define stdin 5
#define stdout 6
#define stderr 0
#endif
in my input/output routines. Although this of course means preprocessing your source file (to do this with ifort, use the -fpp flag when compiling your source code or change the source file extension from .f to .F or from .f90 to .F90).
An alternative to this would be to write your own, non-intrinsic, iso_fortran_env module (if you don't have a Fortran 2003 compiler), as discussed here (this link has died since this answer was posted). In this example they use a module:
module iso_fortran_env
! Nonintrinsic version for Lahey/Fujitsu Fortran for Linux.
! See Subclause 13.8.2 of the Fortran 2003 standard.
implicit NONE
public
integer, parameter :: Character_Storage_Size = 8
integer, parameter :: Error_Unit = 0
integer, parameter :: File_Storage_Size = 8
integer, parameter :: Input_Unit = 5
integer, parameter :: IOSTAT_END = -1
integer, parameter :: IOSTAT_EOR = -2
integer, parameter :: Numeric_Storage_Size = 32
integer, parameter :: Output_Unit = 6
end module iso_fortran_env
As noted in other answers, 0, 5 and 6 are usually stderr, stdin and stdout (this is true for ifort on Linux) but this is not defined by the Fortran standard. Using the iso_fortran_env module is the correct way to portably write to these units.
The Fortran standard doesn't specify which units numbers correspond to stdin/out/err. The usual convention, followed by e.g. gfortran, is that stderr=0, stdin=5, stdout=6.
If your compiler supports the F2003 ISO_FORTRAN_ENV intrinsic module, that module contains the constants INPUT_UNIT, OUTPUT_UNIT, and ERROR_UNIT allowing the programmer to portably retrieve the unit numbers for the preconnected units.
It's actually 0 for stderr. 5 is stdin, 6 is stdout.
For example:
PROGRAM TEST
WRITE(0,*) "Error"
WRITE(6,*) "Good"
END PROGRAM TEST
Gives:
./a.out
Error
Good
while
./a.out 2> /dev/null
Good
I would store a PARAMETER that is STDERR = 0 to make it portable, so if you hit a platform that is different you can just change the parameter.
This example was compiled and run with ifort 12.1.1.256, 11.1.069, 11.1.072 and 11.1.073.
The standard way to write to stdout in Fortran is to put an asterisk instead of the unit number, i.e.,
WRITE(*,fmt) something
or to simply use
PRINT fmt,something
Similarly, the standard way to read from stdin is
READ(*,fmt) something
There is no standard way to write to stderr unless you use ERROR_UNIT from the ISO_FORTRAN_ENV module, which requires Fortran 2003 or later.
Unit numbers 0, 5 and 6 will certainly work in the ifort compiler (and also in some other Fortran compilers), but keep in mind they are compiler-dependent.