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
I want to do something like this (C sample):
char str[] = "Hello\x90\x90\xcc\x00";
How?
The equivalent of this in Fortran would be:
character(*), parameter :: str = "Hello"//char(144)//char(144)//char(204)//char(0)
I made this a named (PARAMETER) constant here, but the expression for initializing would be the same in a normal assignment context. Standard Fortran doesn't allow the use of hex constants (such as Z'90') as an argument to CHAR, though many compilers support that as an extension.
I have the following string:
A = 'A = cos(2*pi*f1*t) + 4*sin(2*pi*f2*t)';
And have defined the variables f1 and f2 (two frequency values) and t (a vector of time points). How I can convert the equation in A to a double-precision value?
I tried:
B = str2num(A); % Result is an empty matrix
and:
B = str2double(A); % Result is a NaN value
and:
B = double(A);
But no luck. How can I do this?
Assuming you have a string like so:
str = 'A = cos(2*pi*f1*t) + 4*sin(2*pi*f2*t)';
And your variables f1, f2, and t have been defined, you would need to use eval to evaluate the string (and you might want to add a ';' to the end to suppress output to the screen):
eval([str ';']);
It should be noted that eval isn't usually the best option, even though sometimes it may be unavoidable. It can have unintended consequences. For example, if a user entered clear all into your uicontrol, it would erase your workspace. They might also inadvertently shadow a function by making a bad choice of variable name, like entering sin = sin(2*pi*f*t). In other words, you should usually try to find alternatives that don't require eval to function.
I have a Maxima program that does some algebra and then writes some things down on an external file. How do I include some calculated values and even small expressions into the name of the file?
A mwe would be the following:
N:3;
f: erf(x);
tay: taylor(f,x,0,N);
with_stdout("taylor.txt", fortran(tay));
But this example names the file taylor.txt. I wanted something that named the file taylor_N3_f_erf.txt or something like that. I have tried several syntaxes but nothing worked.
Also, I know Maxima in programmed in lisp and I learned the syntax for concatenating strings in Lisp but I haven't figured out how to use that in Maxima.
Thank you very much.
Here's what I came up with. It took some playing around with argument quoting and evaluation in functions but I think it works now.
(%i2) bar (name_base, name_extension, ['vars]) := sconcat (name_base, foo(vars), ".", name_extension) $
(%i3) foo(l) := apply (sconcat, join (makelist ("_", 2 * length (l)), join (l, map (string, map (ev, l))))) $
(%i4) [a, b, c] : [123, '(x + 1), '(y/2)];
y
(%o4) [123, x + 1, -]
2
(%i5) bar ("foobar", "txt", a, b, c);
(%o5) foobar_a_123_b_x+1_c_y/2.txt
(%i6) myname : bar ("baz", "quux", a, b);
(%o6) baz_a_123_b_x+1.quux
(%i7) with_stdout (myname, print ("HELLO WORLD"));
(%o7) HELLO WORLD
(%i8) printfile ("baz_a_123_b_x+1.quux");
HELLO WORLD
(%o8) baz_a_123_b_x+1.quux
Note that sconcat concatenates strings and string produces a string representation of an expression.
Division expressions could cause trouble since / means a directory in a file name ... maybe you'll have to subsitute for those characters or any other non-allowed characters. See ssubst.
Note that with_stdout evaluates its first argument, so if you have a variable e.g. myname then the value of myname is the name of the output file.
I've got a variable that could be a number of types - sometimes it's a string, sometimes a number, table or bool. I'm trying to print out the value of the variable each time like this:
print("v: "..v)
with v being my variable. Problem is, when I get a value that can't be concatenated I get this error:
myscript.lua:79: attempt to concatenate a table value
I've tried changing it to this in case it manages to detect whether or not the variable can be printed:
print("v: "..(v or "<can't be printed>"))
but I had the same problem there. Is there some sort of function I can use to determine if a variable can be concatenated to a string, or a better way of printing out variables?
You can provide the values as separate arguments to print:
print("v:", v)
This would print something like
v: table: 006CE900
Not necessarily the most useful, but better than a crash if it's just for debugging purposes.
See here for information on more useful table printing.
tostring(v) works for all possible v values (including nil). So writing your line as:
print( "v: " .. tostring( v ) )
will always work.
Alternatively you could have a look at type( v ) and if its "string" print it, otherwise print something else (if that's what you want).
I was wondering. Are there languages that use only pass-by-reference as their eval strategy?
I don't know what an "eval strategy" is, but Perl subroutine calls are pass-by-reference only.
sub change {
$_[0] = 10;
}
$x = 5;
change($x);
print $x; # prints "10"
change(0); # raises "Modification of a read-only value attempted" error
VB (pre .net), VBA & VBS default to ByRef although it can be overriden when calling/defining the sub or function.
FORTRAN does; well, preceding such concepts as pass-by-reference, one should probably say that it uses pass-by-address; a FORTRAN function like:
INTEGER FUNCTION MULTIPLY_TWO_INTS(A, B)
INTEGER A, B
MULTIPLY_BY_TWO_INTS = A * B
RETURN
will have a C-style prototype of:
extern int MULTIPLY_TWO_INTS(int *A, int *B);
and you could call it via something like:
int result, a = 1, b = 100;
result = MULTIPLY_TWO_INTS(&a, &b);
Another example are languages that do not know function arguments as such but use stacks. An example would be Forth and its derivatives, where a function can change the variable space (stack) in whichever way it wants, modifying existing elements as well as adding/removing elements. "prototype comments" in Forth usually look something like
(argument list -- return value list)
and that means the function takes/processes a certain, not necessarily constant, number of arguments and returns, again, not necessarily a constant, number of elements. I.e. you can have a function that takes a number N as argument and returns N elements - preallocating an array, if you so like.
How about Brainfuck?