I would like to have a Fortran write statement formatted to depend on some variable. For example, I could write:
write(*,'(3f15.3,3f9.2)') x,y,z,(var(i),i=1,nvari)
where nvari = 3. But, what if, in some cases, I actually have 4 variables (i.e. nvari = 4). I would like to write something like this:
write(*,'(3f15.3,nvari(f9.2))') x,y,z,(var(i),i=1,nvari)
Now, nvari can be anything and the output will work as I like. How can I make something like this work?
If you are using Intel fortran, it has a proprietary extension for this -- you can include an existing variable in angle brackets to act as a specifier:
write(*,'(3f15.3,<nvari>f9.2)') x,y,z,(var(i),i=1,nvari)
If you compiler supports it, '(3f15.3, *(f9.2))'
If you have an older compiler, just use a larger number than you will have items to output, e.g., '(3f15.3, 999(f9.2))'. You don't have to use up the format.
For the most complicated cases you can write a format to a string and use that as your format:
write (string, '( "(3f15.3, ", I4, "(f9.2))" )' ) nvari
write (*, string ) x,y,z, (array(i), i=1,nvari)
With the understanding of formats, including format reversion, the use of string formats is rarely necessary.
Instead of writing the format directly in the write statement, it's also possible to use a character variable.
character(len=32) :: my_fmt
my_fmt = '(3f15.3,3f9.2)'
write(*, my_fmt) x, y, z, (var(i), i = 1, nvari)
Now it is possible to manipulate the character variable to contain the wanted repeat count before the write statement, using a so-called internal write, or write to internal file.
write(my_fmt, '(a, i0, a)') '(3f15.3,', nvari, 'f9.2)'
(Just make sure the declared length of my_fmt is long enough to contain the entire character string.)
You wanted to write something like this:
write(*,'(3f15.3,nvari(f9.2))') x, y, z, (var(i), i=1,nvari)
In fact, there is an old trick in the Fortran standard that allows you to omit the nvari, thus:
write(*,'(3f15.3,(f9.2))') x, y, z, (var(i), i=1,nvari)
or even thus:
write(*,'(3f15.3,f9.2)') x, y, z, (var(i), i=1,nvari)
The standard says that the last descriptor in the format is implicitly repeated as often as is necessary to accommodate all of the variables in the list. That 'last descriptor' could be parenthesized such that the last group of descriptors is implicitly repeated, for example:
write(*,'(3f15.3,(2x,f9.2))') x, y, z, (var(i), i=1,nvari)
Related
Consider the variable
character*100 xx
I want to initialize it to some value, possibly some printable character or blanks. I tried
data xx /100*char(120)/
But that did not work.
Minimum working example:
cat car_array.F
character*10 xx
data xx /10*char(120)/
write(*,*)xx
end
ifort car_array.F
car_array.F(2): error #6169: This construct is not valid in this context. [CHAR]
data xx /10*char(120)/
--------------------^
compilation aborted for car_array.F (code 1)
making a bold assumption that you don't really need to be f77 standard compliant,
you should try:
character*10 :: xx=repeat(char(120),10)
in f77 you would have needed to make this a runtime assignment,
character*10 xx
integer i
do i=1,10
xx(i:i)=char(120)
end do
the only way i see to use a repeat count data statement to initialize a string in f77 is via equivalence with a length 1 character array, and here you can not use the char function
equivalence(x,y)
character*10 x
character*1 y(10)
data y/10*'a'/
write(*,*)x
aaaaaaaaaa
Very similar to agentp's post.
You can use the CHAR() function indirectly if you use it in a compile-time PARAMETER statement.
Old-timey, but this works on openVMS Fortran.
PARAMETER CHAR_120 = CHAR(120)
CHARACTER*1 X(10) /10*CHAR_120/
CHARACTER*10 XX
EQUIVALENCE (X, XX)
TYPE *,XX
I'm converting some F77 files to F90. However, there are some common blocks that did not converted. I'm a novice in F90 and have no experience in F77.
Could someone show me how to covert the following example code to F90?
BLOCK DATA SETUP
INTEGER A,B,C
REAL I,J,K,L
COMMON /AREA1/ A,B,C
COMMON /AREA2/ I,J,K,L
DATA A,B,C,I,J,K,L/0,1,2,10.0,-20.0,30.0,-40.0/
END
My idea is to put the arrays A, B, and C in a module. The main thing I don't get here is the AREA1 and AREA2. How are these used in F77 and how do I translate those? My first guess is to discard them and simply define A,B, & C in the module. However, are they a kind of derive type within which A, B, & C are contained?
First up, the original code should compile in Fortran 90 and later. So if it isn't broken, don't try to fix it.
COMMON blocks are basically global variables. In every procedure that the global variables are used, they have to be declared in the same way1, and then they are shared everywhere. Something like this:
integer a, b
common /globals/ a, b
A more modern approach would be to convert globals into a module:
module globals
implicit none
integer a, b
end module globals
And then use that module everywhere you need access to a and b
program main
use globals
implicit none
a = 4
b = 2
end program main
You could either put the DATA statement into the module, or, even easier, initialise every variable in the declaration:
module AREA1
implicit none
integer :: a = 0
integer :: b = 1
integer :: c = 2
end module AREA1
module AREA2
implicit none
real :: i = 10.0
real :: j = -20.0
real :: k = 30.0
real :: l = -40.0
end module AREA2
Then, you can replace the whole thing by just use AREA1 and use AREA2 before the implicit none everywhere you need access to their variables.
Edit: Forgot the footnote
1The rules for common blocks are more flexible, in that the values for the different variables are stored in a common memory location, in the order that they are named. So while it is not technically necessary to always use the same COMMON statement, you can very easily introduce bugs if you don't.
If you have differently named variables (but of the same type), then adapting that is not that hard. Say you have
integer a, b
common /globals/ a, b
in the main program and
integer i, j
common /globals/ i, j
in a subroutine. Assuming that you create a module with a and b, you can then in the subroutine use it in this way:
use globals, only: i => a, j => b
(Note that if you use only, you have to list every variable that you want to use out of the module. You could use something like: only: a, i => b if you want a and i.)
Of course, the following would also be compatible with the previous globals common block, but might lead to more trouble:
integer k(2)
common /globals/ k
I'm parsing a string which may contain either a real or an integral value. I would like to parse that string and get either the integral or the real value in a single parsing.
I could use std::stoi and std::stod, but if i call stoi first and it is a real, then it's going to fail and i will have to call stof, causing a second parsing. And if i call stof first and that the string contains an integral, it's going to consider it as a valid real value, losing the information that it is an integral.
Is there some kind of function that can parse both types in a single pass ? Or do i first have to look for a dot manually and call the right function ?
Thank you. :)
You will not find a standard call to achieve this for the simple reason that a string of digits without a dot is both a valid integer and a valid double.
If your criterion is "double if and only if dot", then look for the dot by hand. Alternatively, read as double and check that the fractional part is null.
Since you said (in the comments above) that simple dot notation is all you want in real numbers, and you want a single-pass (i.e. no back-stepping to already-parsed input), and (again from your comment) are more after the programming experience than efficiency / maintainability / extendability, how about this:
char const * input = /*...*/;
char const * parse_end;
size_t pos;
size_t pos2 = 0;
// parse integer (or pre-digit part of real)
int integer = strtol( input, &parse_end, 10 );
if ( *parse_end == '.' )
{
// you have a real number -- parse the post-digit part
input = parse_end;
double real = strtod( input, &parse_end );
// real + integer is your result
}
else
{
// integer is your result
}
// in either case, parse_end is your position
Why did I use C functions... stoi returns an index, but stod expects a string. So I'd have to do a substr() or similar, while the C functions work with pointers, making things easier.
What I said in my comment holds true: As a brain experiment this holds some value, but any real parsing work should make use of existing solutions like Boost.Spirit. Getting familiar with such building blocks is, IMHO, more valuable than learning how to roll your own.
You should parse it by yourself, using std::string::substr, std::string::find_first_of, std::string::find_first_not_of, etc.
As you know, each of std::stoi and std::stof interprets the first longest substring matching a right representation pattern of required type. You might think the integral-parsed result is always different real-parsed result if both possible, but it isn't.
Example 1: think about "123.". std::stoi will parse the substring "123" and std::stof will parse the whole "123.". "123." is a valid floating-point literal, but it represents an exact integer.
Example 2: think about "123.0". This is a trivial real value representation. std::stoi will parse the substring "123" and std::stof will parse the whole "123.0". Two results evaluate arithmetically same.
This is where you should decide what to parse and what not to. Please see cppreference.com article integer literal and floating-point literal for possible patterns.
With this difficulties, many lexers just tokenize the input (separating it by spaces) and check if the full token matches any of valid representation. I think, If you don't know whether the input is integral or approx real, just parse it by std::stof.
In addition, some solutions casting float to int would cause an erroneous behavior. A float typed variable having integral value is not guaranteed to be evaluated equal to an int typed variable with the same integral value. It's because float, commonly compiled to use float32_t(IEEE 754-1985 single / IEEE 754-2008 binary32) has 24 bits width of significand. So a valid string representation of integer which fits in 32-bit signed, may not fit in float. You lose the precision. double, commonly IEEE 754-2008 binary64, will not lose significand width compared with int32_t, but same problem with int64_t and so on.
I would like to call a C api function from Fortran. The C function accepts an array of bytes:
void image(const void *bitmap, int w, int h);
where three successive bytes in *bitmap represent an RGB colour tripple and are interpreted as unsigned char in C. I want to initialize the bitmap in Fortran and take care of drawing inside C. Current definition in Fortran uses
integer*1 rgbImage(6,2)
to initialize an image of 2x2 for example, but compiler won't accept assignment
rgbImage(1,1) = 255
to get red colour. I've seen hints of using BYTE, UNSIGNED*1, LOGICAL*1 for unsigned single bytes, but gfortran (MacPort's gcc 4.4 or 4.6 under Mac OS X) isn't really happy with either of them. I could probably get away by cheating and assigning value -1 instead of 255, but that is very uncomfortable to use. The compiler flag -fno-range-check helped compile the code, but might not be available in other Fortran compilers and I consider it an ugly solution (I would still want to catch other warning). The values 'FF'X or '11111111'B are also recognized as 32-bit integers.
It is highly desirable for the code to be portable across different Fortran compilers.
My suggestion would be to use CHARACTER variables, and use ACHAR to set values (and ICHAR to convert back to integers as necessary). That should get you what you want and be completely portable. eg,
character, dimension(6,2) :: rgbImage
rgbImage(1,1) = achar(255)
Updated to add: if you're going to use the Fortran 2003 iso_c_binding stuff to interface to the C routines (highly recommended!) then you might as well make that rgbImage array characters of kind c_char, eg
character(kind=c_char), dimension(6,2) :: rgbImage
integer(kind=c_int) :: w, h
...
rgbImage(1,1) = achar(255)
...
call image(rgbImage, w, h)
where you've defined the interface for the routine
interface
subroutine image(img, w, h) bind(C)
use, intrinsic :: iso_c_binding
implicit none
integer(kind=c_int), intent(in), value :: w, h
character(kind=c_char) :: img(:,:)
end subroutine image
end interface
An alternative strategy that may be suitable for some circumstances is to pass the 1 byte c int array to an Integer(1) array, say, iVal(:), then create another Int array such as Integer(2) iVal2(:), then:
Where(iVal(:) < 0)
iVal2(:) = -iVal(:)+127
ElseWhere
iVal2(:) = iVal(:)
End Where
... this can be a bit more efficient/cleaner compared to converting to/fro chars (sometimes) and requires less coding (sometimes).
If you do a lot of this type of thing (interfacing various types of usigned's etc to Fortran), a few utility routines relying on Fortran's bit intrinsics may be a worthwhile investment (e.g. BTest(), iBSet() etc).
I am a total FORTRAN 77 newbie, and I don't understand why the first code shows an error while the second one compiles when I expect them to do the same.
First code (which doesn't compile and gives a error citing an unexpected data declaration statement at z):
program FOO
integer x, y
x = 1
y = 2
integer z
z = 3
end
This code which looks 100% similar in functionality to the first one compiles without errors
program FOO
integer x, y, z
x = 1
y = 2
z = 3
end
I also tried disabling implicit variable declarations in the first code with no effects.
Fortran is one of those quaint "define everything at the top" languages. In other words, this would be fine:
program FOO
integer x, y
integer z
x = 1
y = 2
z = 3
end
since all type specifications are before any executable code. If you're going to define a variable, you should define it first. See here for example:
Such non-executable statements must be placed at the beginning of a program, before the first executable statement.
I don't know real solution but maybe fortran77 doesn't support any code between variables.
for example;
integer x, y, z
x = 1
y = 2
z = 3
works but
integer x, y
x = 1
y = 2
integer z
z = 3
doesn't work. Because between two integer definening (integer x, y and integer z ), there are variables assigning.
#paxdiablo: you think right!
and the errormessage:
"... unexpected data declaration statement at ..."
all DELCARATION must be made BEFORE the first STATEMENT occurs. fortran77 is really "old", I´m not shure if this is changed in F95
For your information: Disabling implicit variable declarations simply removes Fortan's ability to make assumptions about what type your variables are.
Implicit variable declaration makes the following assumptions: Any variable beginning with (capital or lowercase): I, J, K, L, M, or N is to be INTEGER. Any variable beginning with any other letter (capital or lowercase) is to be REAL. This applies only to variables which do not have an explicit type declaration.
You could write:
program FOO
ijk
ifjkask
end
and ijk and ifjkask would be INTEGER values.