How to set a real number as a blank in Fortran? - fortran

I have a list of 500 numbers, and wanted to take a mean of every 10 numbers in that, successively, and thus create an output file with 50 data points. Then it will be further plotted.
But suppose in an interval of 10 all the 10 data are missing, i.e. blank, then I should be able to write correspondingly blank in the output file. But, if my output array is of real type, then I cannot write it as a blank character.
I even tried to create the output array as character type, but, it's showing problem that it cannot write real values to a character type variable.
My question has two points:-
Is there any way that I can store the real variable as blank?
or, How to store real values to character type variable?
I tried the following code to test :-
real r
r=''
write(*,*) r
The output 'r' shows some real value instead.
And for someone suggesting that I should write the output directly to file, I must tell, that I need that output array necessarily for further procedures upon it.

A Fortran real number is always a number, most often in the IEEE floating point format https://en.wikipedia.org/wiki/IEEE_754 . There are some special values, such as not-a-number (NaN) and +-infinity (+Inf, -Inf) but they won't be output as a blank either.
If I understand it correctly, you basically want some sort of an Option type.
You must either check whether the number contains this special value and output a blank if that is the case
if (ieee_is_nan(r)) then
write(*,*)
else
write (*,*) r
end if
or you would have to use some more complicated type
type my_type
real value
logical is_blank =.false.
end type
or you would have to use an allocatable real variable and liave it not allocated if it is blank
if (.not. allocated(r)) then
write(*,*)
else
write (*,*) r
end if

Related

trying to write string in subroutine causing error

Due to some restriction on my assignment, F77 is used.
I am learning to use subroutine but I encounter error when trying to write string out.
PROGRAM test
IMPLICIT NONE
INTEGER a
CHARACTER*20 STR,str1
STR = 'Hello world'
a = 1
WRITE (*,*) a
WRITE (*,10) STR
CALL TEST(str1)
STOP
END
SUBROUTINE test(str2)
CHARACTER*20 str2
str2 = 'testing'
WRITE (*,10) STR2
RETURN
END
When trying to compile this code, it returns that 'Error: missing statement number 10'
Also, I have some other questions:
What does the *20 mean in CHARACTER*20 STR?
Is this the size of the string?
How about 10 in WRITE (*,10) STR? Is this the length of string to be written?
what does (*,*) mean in WRITE (*,*) a
As you can read for example here:
https://www.obliquity.com/computer/fortran/io.html
the second value given to write is an argument for the implicit format keyword, which is the label of a statement within the same program unit, a character expression or array containing the complete format specification, or an asterisk * for list-directed formatting.
Thus if you provide the data directly, you may want to use * there instead.
Otherwise, your program needs to have the label 10 at some line with formatting statement.
And yes, CHARACTER*20 STR means that the variable STR is of length 20, as you can read for instance here: https://www.obliquity.com/computer/fortran/datatype.html
The *20 after CHARACTER specifies the size of the CHARACTER variable (in this case 20 characters). FORTRAN doesn't use null-terminated strings like other languages, instead you have to reserve a specific number of characters. Your actual string can be shorter than the variable, but never longer.
The comma ( , ) in the write statement is used to separate the various arguments. Some versions of FORTRAN allow you to supply 'named' arguments but the default is the first argument is the file code to write to (a '*' implies the standard output). The second argument would be the line number of a FORMAT statement. There can be more arguments, you'd have to look up the specifics for the OPEN statement in your version of FORTRAN.
Some of your WRITE() statements are specifying to use the FORMAT statement found at lable '10'. But your sample doesn't provide any FORMAT statement, so this would be an error.
If you don't want to deal with a FORMAT statement, you can use an asterisk ( * ) as the second argument and then FORTRAN will use a general default format. That is what your first WRITE(,) is doing. It writes to 'stdout' using a general format.

What is the purpose of * in Fortran input/output

I am learning Fortran because well, yeah, thought I'd learn it. However, I've found utterly no information on what the purpose of * is in print, read, etc:
program main
print *, "Hello, world!"
end program main
What is the purpose of this *? I've done some research however I don't think I understand it properly, I don't want to carry on learning until I actually know the point of *.
From what I've managed to find I think that it's some sort of format specifier, however, I don't understand what that means and I have no idea if I'm even correct. All the tutorials I've found just tell me what to write to print to the console but not what * actually means.
You are correct in that it is a format specifier.
There's a page on Wikibooks to do with IO and that states:
The second * specifies the format the user wants the number read with
when talking about the read statement. This applies to the write and print statements too.
For fixed point reals: Fw.d; w is the total number of spaces alloted for the number, and d is the number of decimal places.
And the example they give is
REAL :: A
READ(*,'(F5.2)') A
which reads a real number with 2 digits before and after the decimal point. So if you were printing a real number you'd use:
PRINT '(F5.2)', A
to get the rounded output.
In your example you're just printing text so there's no special formatting to do. Also if you leave the format specifier as * it will apply the default formatting to reals etc.
The print statement does formatted output to a special place (which we assume is the screen). There are three available ways to specify the format used in this output. One of these, as in the question, is using *.
The * format specifier means that the formatted output will be so-called list-directed output. Conversely, for a read statement, it will be list-directed input. Now that the term has been introduced you will be able to find many other questions here: list-directed input/output has many potentially surprising consequences.
Generally, a format specification item says how to format an item in the input/output list. If we are writing out a real number we'd use a format item which may, say, state the precision of the output or whether it uses scientific notation.
As in the question, when writing out a character variable we may want to specify the width of the output field (so that there is blank padding, or partial output) or not. We could have
print '(A20)', "Hello, world!"
print '(A5)', "Hello, world!"
print '(A)', "Hello, world!"
which offers a selection of effects. [Using a literal character constant like '(A)' is one of the other ways of giving the format.]
But we couldn't have
print '(F12.5)', "Hello, world!" ! A numeric format for a character variable
as our format doesn't make sense with the output item.
List-directed output is different from the above cases. Instead, (quote here and later from the Fortran 2008 draft standard) this
allows data editing according to the type of the list item instead of by a format specification. It also allows data to be free-field, that is, separated by commas (or semicolons) or blanks.
The main effect, and why list-directed is such a convenience, is that no effort is required on the part of the programmer to craft a suitable format for the things to be sent out.
When an output list is processed under list-directed output and a real value appears it is as though the programmer gave a suitable format for that value. And the same for other types.
But the crucial thing here is "a suitable format". The end user doesn't get to say A5 or F12.5. Instead of that latter the compiler gets to choose "reasonable processor-dependent values" for widths, precisions and so on. [Leading to questions like "why so much white space?".] The constraints on the output are given in, for example, Fortran 2008 10.10.4.
So, in summary * is saying, print out the following things in a reasonable way. I won't complain how you choose to do this, even if you give me output like
5*0
1 2
rather than
0 0 0 0 0 1 2
and I certainly won't complain about having a leading space like
Hello, world!
rather than
Hello, world!
For, yes, with list-directed you will (except in cases beyond this answer) get an initial blank on the output:
Except for new records created by [a special case] or by continuation of delimited character sequences, each output record begins with a blank character.

Converting integer to character in Fortran90

I am trying to convert an integer to character in my program in Fortran 90.
Here is my code:
Write(Array(i,j),'(I5)') Myarray(i,j)
Array is an integer array and Myarray is a character array, and '(I5)', I don't know what it is, just worked for me before!
Error is:
"Unit has neither been opened not preconnected"
and sometimes
"Format/data mismatch"!
'(I5)' is the format specifier for the write statement: write the value as an integer with five characters in total.
Several thing could go wrong:
Make sure that Myarray really is an integer (and not e.g. a real)
Make sure array is a character array with a length of at least five characters for each element
Take care of the array shapes
Ensure that i and j hold valid values
Here is a working example:
program test
implicit none
character(len=5) :: array(2,2)
integer,parameter :: myArray(2,2) = reshape([1, 2, 3, 4], [2, 2])
integer :: i, j
do j=1,size(myArray,2)
do i=1,size(myArray,1)
write(array(i,j), '(I5)' ) myArray(i,j)
enddo !i
enddo !j
print *, myArray(1,:)
print *, myArray(2,:)
print *,'--'
print *, array(1,:)
print *, array(2,:)
end program
Alexander Vogt explains the meaning of the (I5) part. That answer also points out some other issues and fixes the main problem. It doesn't quite explicitly state the solution, so I'll write that here.
You have two errors, but both have the same cause. I'll re-state your write statement explicitly stating something which is implicit.
Write(unit=Array(i,j),'(I5)') Myarray(i,j)
That implicit thing is unit=. You are, then, asking to write the character variable Myarray(i,j) to the file connected to unit given by the integer variable Array(i,j).
For some values of the unit integer the file is not pre-connected. You may want to read about that. When it isn't you get the first error:
Unit has neither been opened not preconnected
For some values of Array(i,j), say 5, 6 or some other value depending on the compiler, the unit would be pre-connected. Then that first error doesn't come about and you get to
Format/data mismatch
because you are trying to write out a character variable with an integer edit descriptor.
This answer, then, is a long way of saying that you want to do
Write(Myarray(i,j),'(I5)') array(i,j)
You want to write the integer value to a character variable.
Finally, note that if you made the same mistake with a real variable array instead of integer, you would have got a different error message. In one way you just got unlucky that your syntax was correct but the intention was wrong.

fortran format specifier for complex number

Can I specify a format specifier for a complex number in fortran? I have a simple program.
program complx1
implicit none
complex :: var1
var1 = (10,20)
write (*,*) var1
write (*,'(F0.0)') var1
write (*,'(F0.0,A,F0.0)') real(var1), ' + i ' , aimag(var1)
end program complx1
Output:
( 10.0000000 , 20.0000000 )
10.
20.
10. + i 20.
I wanted to use inbuilt format for a+bi with some format specifier, instead of one did manually (second last line of program). Obviously F0.0 did not work. Any ideas?
EDIT:
I don't think this is a duplicate of post: writing complex matrix in fortran, which says to use REAL and AIMAG functions. I already used those functions and wondering whether there is an inbuilt format that can do the work.
An addendum to #francescalus' existing, and mostly satisfactory, answer. A format string such as
fmt = '(F0.0,SP,F0.0,"i")'
should result in a complex number being displayed with the correct sign between real and imaginary parts; no need to fiddle around with strings to get a plus sign in there.
There is no distinct complex edit descriptor. In Fortran 2008, 10.7.2.3.6 we see
A complex datum consists of a pair of separate real data. The editing of a scalar datum of complex type is specified by two edit descriptors each of which specifies the editing of real data.
In your second example, which you say "did not work", you see this formatting in action. Because the format had only one descriptor with no repeat count the values are output in distinct records (format reversion).
The first of your three cases is a very special one: it uses list-directed output. The rules for the output are
Complex constants are enclosed in parentheses with a separator between the real and imaginary parts
There is another useful part of the first rule mentioned:
Control and character string edit descriptors may be processed between the edit descriptor for the real part and the edit descriptor for the imaginary part.
You could happily adapt your second attempt, as we note that your "not working" wasn't because of the use of the complex variable itself (rather than the real and imaginary components)
write (*, '(F0.0,"+i",F0.0)') var1
This, though, isn't right when you have potentially negative complex part. You'll need to change the sign in the middle. This is possible, using a character variable format (rather than literal) with a conditional, but it perhaps isn't worth the effort. See another answer for details of another approach, similar to your third option but more robust.
Another option is to write a function which returns a correctly written character representation of your complex variable. That's like your third option. It is also the least messy approach when you want to write out many complex variables.
Finally, if you do have to worry about negative complex parts but want a simple specification of the variable list, there is the truly ugly
write(*,'(F0.0,"+i*(",F0.0,")")') var1
or the imaginative
character(19) fmt
fmt = '(F0.0,"+",F0.0,"i")'
fmt(8:8) = MERGE('+',' ',var1%im.gt.0)
write(*,fmt) var1
or the even better use of the SP control edit descriptor as given by High Performance Mark's answer which temporarily (for the duration of the output statement) sets the sign mode of the transfer to PLUS which forces the printing of the otherwise optional "+" sign. [Alternatively, this can be set for the connection itself in an open with the sign='plus' specifier.]
All this is because the simple answer is: no, there is no in-built complex edit descriptor.

How to read a list of integers from an input line

Is it possible to read a line with numerous numbers(integers) using Fortran?
lets say i have a file with only only line
1 2 3
the following program reads 3 integers in a line
program reading
implicit none
integer:: dump1,dump2,dump3
read(21,*) dump1,dump2,dump3
end
so dump1=1 dump2=3 dump3=3
If i have a file with only one line but with numerous integers like
1 2 3 4 5 6 7 8 ... 10000
is ti possible the above program to work without defining 10000 variables?
EDIT The first paragraph of this answer might seem rather strange as OP has modified the question.
Your use of the term string initially confused me, and I suspect that it may have confused you too. It's not incorrect to think of any characters in a file, or typed at a command-line as a string, but when all those characters are digits (interspersed with spaces) it is more useful to think of them as integers. The Fortran run-time system will
take care of translating a string of digit characters into an integer.
In that light I think your question might be better expressed as How to read a list of integers from an input line ? Here's one way:
Define an array. Here I define an array of fixed size:
integer, dimension(10**4) :: dump
(I often use expressions such as 10**4 to avoid having to count 0s carefully). This step, defining an array to capture all the values, seems to be the one you are missing.
To read those values from the terminal, at run-time, you might write
write(*,*) 'Enter ', 10**4, 'numbers now'
read(*,*) dump
and this will set dump(1) to the first number you type, dump(2) to the second, all the way to the 10**4-th. Needless to say, typing that number of numbers at the terminal is not recommended and a better approach would be to read them from a file. Which takes you back to your
read(21,*) dump
It wouldn't surprise me to find that your system imposes some limit on the length of a single line so you might have to be more sophisticated when trying to read as many as 10**4 integers, such as reading them in lines of 100 at a time, something like that. That's easy
read(*,*) dump(1:100)
will read 100 integers into the first 100 elements of the array. Write a loop to read 100 lines of 100 integers each.