Check the input data type and whether it is empty or null - fortran

I am asking user to give a value at run time to do some calculations.
I want to test if the user entered value is a real/integer number, and if not then give a warning that the program is expecting a real/integer number here.
In addition, I would as well like to know how do we check if a particular variable at the moment is null or empty. i.e. I have declared a variable but what if at the time of calculation its value is null or empty or not yet set, in that case, the program shouldn't crash instead give a warning to provide a correct value.
Both these operations are much more easier in C++ and C#, but I couldn't find a way to do that in Fortran.

I guess that "null or empty" you mean whether a variable has been initialized: "not yet set". "null" has a particular meaning for Fortran pointer variables, but I suppose that this is not your question.
Fortran doesn't automatically give variables a special value before they are intentionally initialized so there is no easy way to check whether a variable has been initialized. One approach is to initialize the variable its declaration with a special value. That means that you need to know a special value that it will never obtain in the operation of the program. One possibility is to use the huge intrinsic:
program TestVar
real :: AVar = huge (1.0)
if ( AVar < huge (1.0) ) then
write (*, *) "Test 1: Good"
else
write (*, *) "Test 1: Bad"
end if
AVar = 2.2
if ( AVar < huge (1.0) ) then
write (*, *) "Test 2: Good"
else
write (*, *) "Test 2: Bad"
end if
end program TestVar
As warned by #arbautjc, this only works once, even in a subroutine. In a procedure, the initialization with declaration is only done with a first call. Also, if you change the variable type from this example, be sure to understand how huge works (e.g., Long ints in Fortran).

Related

How to set a real number as a blank in 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

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.

Assumed string length input into a Fortran function

I am writing the following simple routine:
program scratch
character*4 :: word
word = 'hell'
print *, concat(word)
end program scratch
function concat(x)
character*(*) x
concat = x // 'plus stuff'
end function concat
The program should be taking the string 'hell' and concatenating to it the string 'plus stuff'. I would like the function to be able to take in any length string (I am planning to use the word 'heaven' as well) and concatenate to it the string 'plus stuff'.
Currently, when I run this on Visual Studio 2012 I get the following error:
Error 1 error #6303: The assignment operation or the binary
expression operation is invalid for the data types of the two
operands. D:\aboufira\Desktop\TEMP\Visual
Studio\test\logicalfunction\scratch.f90 9
This error is for the following line:
concat = x // 'plus stuff'
It is not apparent to me why the two operands are not compatible. I have set them both to be strings. Why will they not concatenate?
High Performance Mark's comment tells you about why the compiler complains: implicit typing.
The result of the function concat is implicitly typed because you haven't declared its type otherwise. Although x // 'plus stuff' is the correct way to concatenate character variables, you're attempting to assign that new character object to a (implictly) real function result.
Which leads to the question: "just how do I declare the function result to be a character?". Answer: much as you would any other character variable:
character(len=length) concat
[note that I use character(len=...) rather than character*.... I'll come on to exactly why later, but I'll also point out that the form character*4 is obsolete according to current Fortran, and may eventually be deleted entirely.]
The tricky part is: what is the length it should be declared as?
When declaring the length of a character function result which we don't know ahead of time there are two1 approaches:
an automatic character object;
a deferred length character object.
In the case of this function, we know that the length of the result is 10 longer than the input. We can declare
character(len=LEN(x)+10) concat
To do this we cannot use the form character*(LEN(x)+10).
In a more general case, deferred length:
character(len=:), allocatable :: concat ! Deferred length, will be defined on allocation
where later
concat = x//'plus stuff' ! Using automatic allocation on intrinsic assignment
Using these forms adds the requirement that the function concat has an explicit interface in the main program. You'll find much about that in other questions and resources. Providing an explicit interface will also remove the problem that, in the main program, concat also implicitly has a real result.
To stress:
program
implicit none
character(len=[something]) concat
print *, concat('hell')
end program
will not work for concat having result of the "length unknown at compile time" forms. Ideally the function will be an internal one, or one accessed from a module.
1 There is a third: assumed length function result. Anyone who wants to know about this could read this separate question. Everyone else should pretend this doesn't exist. Just like the writers of the Fortran standard.

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 return statement

I'm trying to get some code compiled under gfortran that compiles fine under g77. The problem seems to be from a return statement:
ffuncs.f:934.13:
RETURN E
1
Error: Alternate RETURN statement at (1) requires a SCALAR-INTEGER return specifier
In the code anything E was specified as real*8:
IMPLICIT REAL*8 ( A - H , O -Z )
However, E was never given a value or anything in fact you never see it until the return statement. I know almost nothing about fortran. What is the meaning of a return statement with an argument in fortran?
Thanks.
In FORTRAN (up to Fortran 77, which I'm very familiar with), RETURN n is not used to return a function value; instead, it does something like what in other languages would be handled by an exception: An exit to a code location other than the normal one.
You'd normally call such a SUBROUTINE or FUNCTION with labels as arguments, e.g.
CALL MYSUB(A, B, C, *998, *999)
...
998 STOP 'Error 1'
998 STOP 'Error 2'
and if things go wrong in MYSUB then you do RETURN 1 or RETURN 2 (rather than the normal RETURN) and you'd be hopping straight to label 998 or 999 in the calling routine.
That's why normally you want an integer on that RETURN - it's not a value but an index to which error exit you want to take.
RETURN E sounds wrong to me. Unless there's a syntax I'm unaware of, the previous compiler should have flagged that as an error.
In a Fortran function one returns the value, by assigning the value to a fake variable which is the same name as the function. Once you do that, simply return.
I think #Carl Smotricz has the answer. Does argument list of ffuncs has dummy arguments that are asterisks (to match the asterisk-label in the calls)? Or was this used without there being alternative returns? If there were no alternative returns, just delete the "E". If there are alternative returns, the big question is what the program was doing before at run time since the variable was of the wrong type and uninitialized. If the variable didn't have an integer value matching one of the expected branches, perhaps the program took the regular return branch -- but that's just a guess -- if so, the easy fix is to again to delete the "E".
The "alternate return" feature is considered "obsolescent" by the language standard and could be deleted in a future standard; compilers would likely continue to support it if it were removed because of legacy code. For new code, one simple alternative is to return an integer status variable and use a "select case" statement in the caller.