Joseph Hallstrom
Joseph Hallstrom

Reputation: 13

Incorrect output with '(23A, 1X, F4.1, 2X, 1A)' format

I am writing my first FORTRAN program since 1989 (using FORTRAN77) and this is my introduction to a modern FORTRAN. I am having trouble with formatting write statements. Specifically, after reading a REAL value and a CHARACTER, I then use a formatted WRITE statement to allow the user to review the input. I can use an unformatted WRITE statement and everything is fine, however, if I use a simple formatting statement, the resulting output is garbage. The following is my MWE:

! MWE program testing formatted write of a real number
!
! bash cmd line gfortran-9 -o MWE_formated_write MWE_formated_write.f95
! build environment:
!   Kubuntu 21.04 / kernel 5.11.0-34-generic
!   GNU Fortran (Ubuntu 9.3.0-23ubuntu2) 9.3.0
!   laptop w/ 4x Intel i5-5200U @ 2.2 GHz w/ 8 GiB ram
!
program MWE_formated_write
!
implicit none
real :: temp_input                     ! input temperature
character(len=1) :: temp_input_units   ! input temperature unit, [F]/[C]/[R]/[K]
!
! Get input temperature and temperature units
!
write(*,*) "Enter the temperature and units F/C/R/K: "
read(*,*) temp_input, temp_input_units
!
! verify the input temperature and temperature units
!
write(*, *) "     You entered (raw):", temp_input, temp_input_units
write(*, '(23A, 1X, F4.1, 2X, 1A)') "You entered (formated):", temp_input, temp_input_units
!
stop
end program MWE_formated_write

and a capture of the output:

joseph@bohr:~/Projects$ gfortran-9 -o MWE_formated_write MWE_formated_write.f95
joseph@bohr:~/Projects$ ./MWE_formated_write
 Enter the temperature and units F/C/R/K:
95 F
      You entered (raw):   95.0000000     F
You entered (formated):�BF

I expected the second line to output "You entered (formated): 95.1 F".

Upvotes: 1

Views: 89

Answers (1)

Scientist
Scientist

Reputation: 1835

There is a simple bug in your code, where the format field reads 23A. This means there are 23 character objects to print on stdout while in reality there is only 1. I suppose what you meant was a single character object with a width of 23. But even 23 is likely too small for the output string which has a length of 23. Perhaps a number like 30 would be more appropriate. Then, there is the issue of the width of the real number which is requested to be only 4, which is in most cases too narrow. In general, it is good to specify a width of at least 7 characters more than the specified precision (here 1). The following resolves both issues. But even better is to use the modern Fortran generic descriptor g0 which takes care of all types of objects automatically. The full description of the g0 edit descriptor is rather lengthy, but it effectively removes the burden of specifying the widths and types of records from the user and leaves it to the compiler. The g0.d specification means that if the compiler encounters a real number, then it should set the precision of the output record to d digits after the decimal point, otherwise it is ignored for a character or integer output.

The ' ' in the format forced the compiler to separate each output record with a single whitespace. Change it to ',' and it becomes a comma-delimited set of values (CSV).

The : in the format has an interesting story of being a typo in the Fortran 2008 standard, but now has the utility of skipping the addition of the last separator, which in this case is a single white space " ".

program MWE_formated_write

    use iso_fortran_env, only: RK => real64
    implicit none
    real(RK)            :: temp_input         ! input temperature
    character(len=1)    :: temp_input_units   ! input temperature unit, [F]/[C]/[R]/[K]

    ! Get input temperature and temperature units

    write(*,"(*(g0.10,:,' '))") "Enter the temperature and units F/C/R/K: "
    read(*,*) temp_input, temp_input_units
    write(*,*) temp_input, temp_input_units

    ! verify the input temperature and temperature units

    write(*,"(*(g0,:,' '))") "     You entered (raw):", temp_input, temp_input_units
    write(*, '(A30, 1X, F10.1, 2X, 1A)') "You entered (formated):", temp_input, temp_input_units

end program MWE_formated_write

Here is the output of the program with Intel ifort:

Enter the temperature and units F/C/R/K: 123 C  
123.000000000000      C  
You entered (raw): 123.0000000000000 C  
You entered (formated):      123.0  C

Upvotes: 1

Related Questions