I am looking for a way to read numerical expressions in Fortran.
With numerical expression I mean dsqrt(0.5d0)/3.d0+1.d0 or something rather then the translated 1.235... real version.
With reading I mean
open(unit=UnitNumber,file="FileName")
read(UnitNumber, *) ....
I try to define in the reading statement the format, for instanceread(unitNumber,"(15F24.17)") but it does not help. I am
I am wondering if I can do it only internally, defining real(8), parameter :: dsqrt(0.5d0)/3.d0+1.d0 .
Maybe the use of FORMAT syntax could help?
As suggested by #agentp, interpreted languages like Python and Julia can parse a string directly as a piece of code, so utilizing such a feature may be convenient for your purpose. But if you definitely need to achieve the same goal in Fortran, another approach (with least effort!) may be simply to call eval() in such languages, for example:
module util
use iso_fortran_env, only: dp => real64
implicit none
contains
subroutine eval( expr, ans, x, y )
character(*), intent(in) :: expr
real(dp), intent(out) :: ans
real(dp), intent(in), optional :: x, y
character(len(expr)+200) cmd, sx, sy
integer u
sx = "" ; sy = ""
if ( present(x) ) write( sx, "(' x = ', es25.15, ' ; ')" ) x
if ( present(y) ) write( sy, "(' y = ', es25.15, ' ; ')" ) y
write( cmd, "(a)" ) &
"python -c ""from __future__ import print_function, division ; " // &
"from math import * ; " // trim(sx) // trim(sy) // &
"print( eval( '" // trim(expr) // "' ))"" > tmp.dat"
call system( trim( cmd ) )
open( newunit=u, file="tmp.dat", status="old" )
read( u, * ) ans
close( u )
call system( "rm -f tmp.dat" )
end subroutine
end module
program main
use util, only: dp, eval
implicit none
character(200) str
real(dp) ans
str = "sqrt( 2.0 ) + 1000.0"
call eval( str, ans )
print *, "ans = ", ans
str = "acos( x ) + 2000.0"
call eval( str, ans, x= -1.0_dp )
print *, "ans = ", ans
str = "10 * x + y"
call eval( str, ans, x= 1.0_dp, y= 2.0_dp )
print *, "ans = ", ans
end program
Results:
$ gfortran test.f90 # gfortran >=5 is recommended
$ ./a.out
ans = 1001.4142135623731
ans = 2003.1415926535899
ans = 12.000000000000000
More specifically, the above code simply invokes the built-in eval() function in Python via system(). But it is not very efficient because the resulting value is once written to an external file (and also the overhead to call Python itself). So if efficiency matters, it may be better to use more specific 3rd-party libraries, or for handiness, work with interpreted languages directly. (I suggest the latter approach if the calculation is not too demanding, because it saves much time for coding...)
Python:
from __future__ import print_function, division
from math import *
str = input( "Input an expression: " )
x = 1.0
y = 2.0
print( eval( str ) ) # if you type "x + 10 * y" in the prompt, you get 21
Julia:
println( "Input an expression: " )
str = readline()
x = 1.0
y = 2.0
println( eval( parse( str ) ) )
[ EDIT ]
If it is OK to use system() and write external files, another option may be to simply write a small Fortran code that contains the expression to be evaluated, compile and run it via system(), get the result via an external file. For example, if we replace the two lines in the above code (write( cmd, "(a)" ) ... and system( trim( cmd ) )) by the following, it gives the same result. This might be useful if we want to keep the code entirely written in Fortran, with minimal effort for modification.
open( newunit=u, file="tmp.f90" )
write( u, "(a)" ) "implicit none"
write( u, "(a)" ) "real :: x, y"
write( u, "(a)" ) trim(sx)
write( u, "(a)" ) trim(sy)
write( u, "(a)" ) "write(*,'(e30.20)') " // trim(expr)
write( u, "(a)" ) "end"
close( u )
call system( "gfortran -fdefault-real-8 -ffree-line-length-none tmp.f90 && ./a.out > tmp.dat" )
! Assuming bash on Linux or Mac (x86_64).
! -fdefault-real-8 is attached to promote 1.0 etc to 8-byte floating-point values.
call system( "rm -f tmp.f90" )
For the record, the library fparser allows you to do precisely what you asked for: evaluate a string as a mathematical expression within Fortran, without requiring any other programming languages.
No, there is nothing like this built in Fortran or any related programming languages. There are specific libraries for similar purposes (not necessarily too many in Fortran).
It is not clear at all to me why do you want that and how do you intend to use such an expression. It would have to be some specific type and you would need specific subroutines to evaluate such an expression.
Related
I am new to Perl and I'm trying to create a simple calculator program, but the rules are different from normal maths. All operations have the same power and the math problem must be solved from left to right.
Here is an example:
123 - 10 + 4 * 10 = ((123 - 10) + 4) * 10 = 1170
8 * 7 / 3 + 2 = ((8 * 7) / 3) + 2 = 20.666
So in the first case the user needs to enter one string: 123 - 10 + 4 * 10.
How do i approach this task?
I'm sorry if it's too much of a general question, but i'm not sure how to even begin. Do i need a counter? Like - every second character of the string is an operator, while the two on the sides are digits.
I'm afraid I'm lazy so I'll parse with a regex and process as I parse.
#!/usr/bin/env perl
#use Data::Dumper;
use Params::Validate (':all');
use 5.01800;
use warnings;
my $string=q{123 - 10 + 4 * 10};
my $result;
sub fee {
my ($a)=validate_pos(#_,{ type=>SCALAR });
#warn Data::Dumper->Dump([\$a],[qw(*a)]),' ';
$result=$a;
};
sub fi {
my ($op,$b)=validate_pos(#_,{ type=>SCALAR},{ type=>SCALAR });
#warn Data::Dumper->Dump([\$op,\$b],[qw(*op *b)]),' ';
$result = $op eq '+' ? $result+$b :
$op eq '-' ? $result-$b :
$op eq '*' ? $result*$b :
$op eq '/' ? $result/$b :
undef;
#warn Data::Dumper->Dump([\$result],[qw(*result)]),' ';
};
$string=~ m{^(\d+)(?{ fee($1) })(?:(?: *([-+/*]) *)(\d+)(?{ fi($2,$3) }))*$};
say $result;
Note the use of (?{...}) 1
To be clear, you are not looking for a regular calculator. You are looking for a calculator that bends the rules of math.
What you want is to extract the operands and operators, then handle them 3 at the time, with the first one being the rolling "sum", the second an operator and the third an operand.
A simple way to handle it is to just eval the strings. But since eval is a dangerous operation, we need to de-taint the input. We do this with a regex match: /\d+|[+\-*\/]+/g. This matches either 1 or more + digits \d or |, 1 or more + of either +-*/. And we do this match as many times as we can /g.
use strict;
use warnings;
use feature 'say';
while (<>) { # while we get input
my ($main, #ops) = /\d+|[+\-*\/]+/g; # extract the ops
while (#ops) { # while the list is not empty
$main = calc($main, splice #ops, 0, 2); # take 2 items off the list and process
}
say $main; # print result
}
sub calc {
eval "#_"; # simply eval a string of 3 ops, e.g. eval("1 + 2")
}
You may wish to add some input checking, to count the args and make sure they are the correct number.
A more sensible solution is to use a calling table, using the operator as the key from a hash of subs designed to handle each math operation:
sub calc {
my %proc = (
"+" => sub { $_[0] + $_[1] },
"-" => sub { $_[0] - $_[1] },
"/" => sub { $_[0] / $_[1] },
"*" => sub { $_[0] * $_[1] }
);
return $proc{$_[1]}($_[0], $_[2]);
}
As long as the middle argument is an operator, this will perform the required operation without the need for eval. This will also allow you to add other math operations that you might want for the future.
Just to read raw input from the user you would simply read the STDIN file handle.
$input = <STDIN>;
This will give you a string, say "123 + 234 - 345" which will have a end of line marker. You can remove this safely with the chomp command.
After that you will want to parse your string to get your appropriate variables. You can brute force this with a stream scanner that looks at each character as you read it and processes it accordingly. For example:
#input = split //, $input;
for $ch (#input) {
if ($ch > 0 and $ch <= 9) {
$tVal = ($tVal * 10) + $ch;
} elsif ($ch eq " ") {
$newVal = $oldVal
} elsif ($ch eq "+") {
# Do addition stuff
}...
}
Another approach would be to split it into words so you can just deal with whole terms.
#input = split /\s+/, $input;
Instead of a stream of characters, as you process the array values will be 123, +, 234, -, and 345...
Hope this points you in the right direction...
This question already has answers here:
Obtaining current host name from Cray Fortran
(3 answers)
Closed 6 years ago.
I am running a fortran code on a cluster equiped with linux system. When the code begin to run, I want it to output some basic information of the node where it is running, especially the node name. How to do it in fortran.
If your code is parallelised with MPI - which is kind of common for a code running on a cluster - then just call MPI_Get_processor_name() that just does exactly this.
If not, just use the iso_c_binding module to call the C function gethostname(), which again just does that.
EDIT: here is an example on how to call gethostname() with the iso_c_binding module. I'm definitely not an expert with that so it might not be the most effective one ever...
module unistd
interface
integer( kind = C_INT ) function gethostname( hname, len ) bind( C, name = 'gethostname' )
use iso_c_binding
implicit none
character( kind = C_CHAR ) :: hname( * )
integer( kind = C_INT ), VALUE :: len
end function gethostname
end interface
end module unistd
program hostname
use iso_c_binding
use unistd
implicit none
integer( kind = C_INT ), parameter :: sl = 100
character( kind = C_CHAR ) :: hn( sl )
character( len = sl ) :: fn
character :: c
integer :: res, i, j
res = gethostname( hn, sl )
if ( res == 0 ) then
do i = 1, sl
c = hn( i )
if ( c == char( 0 ) ) exit
fn( i: i ) = c
end do
do j = i, sl
fn( j: j ) = ' '
end do
print *, "->", trim( fn ), "<-"
else
print *, "call to gethostname() didn't work..."
end if
end program hostname
If the information you want is contained in an environment variable the easy way is just to get its value from a call to get_environment_variable. For the hostname
program gethost
character*32 hostname
call get_environment_variable('HOST',hostname)
write(*,*) 'My gracious host is ',trim(hostname)
end program gethost
I am using the app TouchLua.
I need to turn a string from a table into an argument. This is the only way I would like to do the table.
b = {}
b[1] = "010,010,draw.blue"
function drawButtons()
for i = 1,2 do
draw.fillrect(tonumber(string.sub(b[i],1,3)), tonumber(string.sub(b[i],5,7)), tonumber(string.sub(b[i],1,3))+10, tonumber(string.sub(b[i],5,7)),string.sub(b[i],9))
end
end
drawButtons()
Assuming you want a function eval so that print( eval( "draw.blue" ) ) is roughly equivalent to print( draw.blue ), here is a quick and dirty version:
local function eval( s, e )
return assert( load( "return "..s, "=eval", "t", e or _G ) )()
end
-- global variable
draw = { blue = 2 }
print( draw.blue )
print( eval( "draw.blue" ) )
If you are using an older Lua version than 5.2, you will need loadstring instead of load and an additional setfenv call. Of course, instead of using load you can parse the string s and index the table e or _G manually.
The above code assumes that draw is a global variable. If you want the code to work with a local variable you need to use the debug library:
-- same for local variable
local localdraw = { blue = 3 }
print( localdraw.blue )
-- needs debugging information, so won't work with stripped bytecode!
local function locals()
local t, i, n, v = {}, 1, debug.getlocal( 2, 1 )
while n ~= nil do
t[ n ], i = v, i+1
n, v = debug.getlocal( 2, i )
end
return t
end
print( eval( "localdraw.blue", locals() ) )
I want to convert string text to table and this text must be divided on characters. Every character must be in separate value of table, for example:
a="text"
--converting string (a) to table (b)
--show table (b)
b={'t','e','x','t'}
You could use string.gsub function
t={}
str="text"
str:gsub(".",function(c) table.insert(t,c) end)
Just index each symbol and put it at same position in table.
local str = "text"
local t = {}
for i = 1, #str do
t[i] = str:sub(i, i)
end
The builtin string library treats Lua strings as byte arrays.
An alternative that works on multibyte (Unicode) characters is the
unicode library that
originated in the Selene project.
Its main selling point is that it can be used as a drop-in replacement
for the string library, making most string operations “magically”
Unicode-capable.
If you prefer not to add third party dependencies your task can easily
be implemented using LPeg.
Here is an example splitter:
local lpeg = require "lpeg"
local C, Ct, R = lpeg.C, lpeg.Ct, lpeg.R
local lpegmatch = lpeg.match
local split_utf8 do
local utf8_x = R"\128\191"
local utf8_1 = R"\000\127"
local utf8_2 = R"\194\223" * utf8_x
local utf8_3 = R"\224\239" * utf8_x * utf8_x
local utf8_4 = R"\240\244" * utf8_x * utf8_x * utf8_x
local utf8 = utf8_1 + utf8_2 + utf8_3 + utf8_4
local split = Ct (C (utf8)^0) * -1
split_utf8 = function (str)
str = str and tostring (str)
if not str then return end
return lpegmatch (split, str)
end
end
This snippet defines the function split_utf8() that creates a table
of UTF8 characters (as Lua strings), but returns nil if the string
is not a valid UTF sequence.
You can run this test code:
tests = {
en = [[Lua (/ˈluːə/ LOO-ə, from Portuguese: lua [ˈlu.(w)ɐ] meaning moon; ]]
.. [[explicitly not "LUA"[1]) is a lightweight multi-paradigm programming ]]
.. [[language designed as a scripting language with "extensible ]]
.. [[semantics" as a primary goal.]],
ru = [[Lua ([лу́а], порт. «луна») — интерпретируемый язык программирования, ]]
.. [[разработанный подразделением Tecgraf Католического университета ]]
.. [[Рио-де-Жанейро.]],
gr = [[Η Lua είναι μια ελαφρή προστακτική γλώσσα προγραμματισμού, που ]]
.. [[σχεδιάστηκε σαν γλώσσα σεναρίων με κύριο σκοπό τη δυνατότητα ]]
.. [[επέκτασης της σημασιολογίας της.]],
XX = ">\255< invalid"
}
-------------------------------------------------------------------------------
local limit = 14
for lang, str in next, tests do
io.write "\n"
io.write (string.format ("<%s %3d> ->", lang, #str))
local chars = split_utf8 (str)
if not chars then
io.write " INVALID!"
else
io.write (string.format (" <%3d>", #chars))
for i = 1, #chars > limit and limit or #chars do
io.write (string.format (" %q", chars [i]))
end
end
end
io.write "\n"
Btw., building a table with LPeg is significantly faster than calling
table.insert() repeatedly.
Here are stats for splitting the whole of Gogol’s Dead Souls (in
Russian, 1023814 bytes raw, 571395 characters UTF) on my machine:
library method time in ms
string table.insert() 380
string t [#t + 1] = c 310
string gmatch & for loop 280
slnunicode table.insert() 220
slnunicode t [#t + 1] = c 200
slnunicode gmatch & for loop 170
lpeg Ct (C (...)) 70
You can below code to achieve this easily.
t = {}
str = "text"
for i=1, string.len(str) do
t[i]= (string.sub(str,i,i))
end
for k , v in pairs(t) do
print(k,v)
end
-- 1 t
-- 2 e
-- 3 x
-- 4 t
Using string.sub
string.sub(s, i [, j])
Return a substring of the string passed. The substring starts at i. If the third argument j is not given, the substring will end at the end of the string. If the third argument is given, the substring ends at and includes j.
I'm looking for a boolean interpolation character for string.format(as the title says).
I want something that will work this way:
print(string.format("nil == false: %b",(nil==false))
%b is just a placeholder, you'll get an error with that. I'm looking for 'b'. I can't
just do:
print("nil == false: " .. (nil==false))
because booleans can't be concatenated with strings. I could do:
val=(nil==false)
if val==false then truth="false" else truth="true" end
print("nil==false: ".. truth)
But it's too much work.
If you're wondering how to modify string.format so it supports bools, here's one way you can do it:
do
local format = string.format
function string.format(str, ...)
local args = {...}
local boolargs = {}
str = str:gsub("%%b", "%%%%b")
for i = #args, 1, -1 do
if type(args[i]) == "boolean" then
table.insert(boolargs, 1, args[i])
table.remove(args, i)
end
end
str = format(str, unpack(args))
local j = 0
return (str:gsub("%%b", function(spec) j = j + 1; return tostring(boolargs[j]) end))
end
end
print(string.format("%s is %b", "nil == false", nil==false))
It might be a bit confusing to follow. The idea is to gsub all "%b" in the string and replace it with double escape %%b so format doesn't try to interpret it. We let string.format do its stuff and we take the result and handle %b manually ourselves.
Well, first you should try reading the relevant section of the manual. That will let you discover that there is no format specifier for booleans.
What greatwolf suggests is a solution, i.e. converting the value explicitly to a string. If there is a possibility that your truth value may be nil, but you want to output it as false, this trick is useful:
truth = nil
print("nil==false: ".. tostring( not not truth ))
In this way both nil and false will be displayed as false.
Edit (to answer a comment)
In Lua 5.2 the %s specifier automatically convert the arguments to strings using tostring internally. Thus:
print( string.format( "%s %s %s", true, nil, {} ) )
prints:
true nil table: 00462400
otherwise you can create your own formatting function wrapping string.format:
local function myformat( fmt, ... )
local buf = {}
for i = 1, select( '#', ... ) do
local a = select( i, ... )
if type( a ) ~= 'string' and type( a ) ~= 'number' then
a = tostring( a )
end
buf[i] = a
end
return string.format( fmt, unpack( buf ) )
end
print( myformat( "%s %s %s", true, nil, {} ) )