Is there an equivalent for the 'a' format specifier known from C in Fortran?
C Example:
printf("%a\n",43.1e6); // 0x1.48d3bp+25
Exporting floating point numbers in hexadecimal format prevents rounding errors. While the rounding errors are usually negligible, it is still advantageous to be able to restore a saved value exactly. Note, that the hexadecimal representation produced by printf is portable and human readable.
How can I export and parse floating point numbers in Fortran like I do in C using the 'a' specifier?
If you want to have full precision, the best way is to use unformatted files, such as this:
program main
real :: r
integer :: i
r = -4*atan(1.)
open(20,access="stream")
write (20) r
close(20)
end program main
(I used stream access, which is new to Fortran 2003, because
it is usually less confusing than normal unformatted access). You can then use, for example, od -t x1 fort.20 to look at this as a hex dump.
You can also use TRANSFER to copy the bit pattern to an integer and then use the Z edit descriptor.
If you really want to mimic the %a specifier, you'll have to roll your own. Most machines now use IEEE format. Use TRANSFER for copying the pattern to an integer, then pick that apart using IAND (and multiplications or divisions by powers of two for shifting).
Another option would be to let the C library do your work for you and interface via C binding. This rather depends on a modern compiler (some F2003 features used).
module x
use, intrinsic :: iso_c_binding
private
public :: a_fmt
interface
subroutine doit(a, dest, n) bind(C)
import
real(kind=c_double), value :: a
character(kind=c_char), intent(out) :: dest(*)
integer, value :: n
end subroutine doit
end interface
interface a_fmt
module procedure a_fmt_float, a_fmt_double
end interface a_fmt
contains
function a_fmt_float(a) result(res)
real(kind=c_float), intent(in) :: a
character(len=:), allocatable :: res
res = a_fmt_double (real(a, kind=c_double))
end function a_fmt_float
function a_fmt_double(a) result(res)
real(kind=c_double), intent(in) :: a
character(len=:), allocatable :: res
character(len=30) :: dest
integer :: n
call doit (a, dest, len(dest))
n = index(dest, achar(0))
res = dest(1:n)
end function a_fmt_double
end module x
program main
use x
implicit none
double precision :: r
integer :: i
r = -1./3.d0
do i=1,1030
print *,a_fmt(r)
r = - r * 2.0
end do
end program main
#include <stdio.h>
void doit (double a, char *dest, int n)
{
snprintf(dest, n-1, "%a", a);
}
Related
I need to pass a vector of pointers from c++ to a Fortran dll and I do not know if this is possible.
I tried searching but I could not really find and answer to my question.
The idea is the following:
Fortran side
!DEC$ATTRIBUTES DLLEXPORT :: TO_FORTRAN
integer function TO_FORTRAN (test4) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
REAL, intent(in) :: test4(3)
REAL, pointer :: test5
call C_F_POINTER(C_LOC(test4),test5)
TO_FORTRAN = 0
END
c++ code
std::vector<float> test1(3);
std::vector<float> test2(3);
std::vector<float> test3(3);
std::vector<float*> test4(3);
test4[0] = test1.data();
test4[1] = test2.data();
test4[2] = test3.data();
TO_FORTRAN(test4);
If it is really an array of pointers, you need to treat it like an array of pointers at the Fortran side as well. You also have keep in mind they are pointers to arrays, not just scale real numbers (although they may be represented the same way in C).
!DEC$ATTRIBUTES DLLEXPORT :: TO_FORTRAN
integer function TO_FORTRAN (test4) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
type(c_ptr), intent(in) :: test4(3)
REAL, pointer :: test1(:), test2(:), test3(:)
call C_F_POINTER(test4(1),test1, [3])
call C_F_POINTER(test4(2),test2, [3])
call C_F_POINTER(test4(3),test3, [3])
TO_FORTRAN = 0
END FUNCTION
and
TO_FORTRAN(test4.data());
I'm beginning with Fortran 2008 and I'm struggling with OOP greatly. It seems, that there are very few materials, which explain a very basic OOP concepts in 2008 language standard.
I've found information about inheritance, but I was unable to find any info about polymorphism.
So if I wanted to overload a function in C++, I can do it like this (example from Wikipedia):
// volume of a cube
int volume(const int s)
{
return s*s*s;
}
// volume of a cylinder
double volume(const double r, const int h)
{
return 3.1415926*r*r*static_cast<double>(h);
}
// volume of a cuboid
long volume(const long l, const int b, const int h)
{
return l*b*h;
}
But, how am I supposed to do the same thing in Fortran 2008?
The idea of overloading as given in the C++ examples has an implementation in Fortran, dating back to the generics of Fortran 90.
Given a set of specific procedures a generic identifier may be used to identify this set. In this answer I'll give a very high-level introduction to this concept. There are a lot of subtleties which may require further reading/questions to address.
Unlike the C++ example, our Fortran specific procedures need to be named separately. Let's have the two functions (third can be added mutatis mutandis)
integer function volume_cube(s)
integer, intent(in) :: s
...
end function volume_cube
double precision function volume_cylinder(r, h)
double precision, intent(in) :: r
integer, intent(in) :: h
...
end function volume_cylinder
We can then add a generic interface for something called volume:
interface volume
procedure volume_cube, volume_cylinder
end interface
We can then reference the generic volume and the compiler will determine which specific function to use.
There is much more to learn about generics, including what else they offer beyond this simple overloading. One should also understand how specific procedures are resolved (simple in this case, not so in others) and the restrictions on which specific procedures may be lumped together. As you use generics problematic cases are likely to have particular questions. I answer here only as I couldn't see an introductory question and I don't attempt to address the many varied difficulties or values.
Complete example
module mod
private
interface volume
module procedure volume_cube, volume_cylinder
end interface volume
public volume
contains
integer function volume_cube(s)
integer, intent(in) :: s
volume_cube = s**3
end function volume_cube
double precision function volume_cylinder(r, h)
double precision, intent(in) :: r
integer, intent(in) :: h
volume_cylinder = 3.1415926d0*r**2*h
end function volume_cylinder
end module mod
use mod
print*, volume(2), volume(2d0,4)
end
expanding Fancescalus example:
module Pablo_Dali
private
interface volume_Cube
module procedure volume_cube_Int, volume_cube_Float, Colume_cube_Double
!add in 8, 16, and 64 bit ints... and complex??
end interface volume
public volume_Cube
contains
integer function volume_cube_Int(s)
integer, intent(in) :: s
volume_cube_Int = s**3
end function volume_cube_int
float function volume_cube_Float(s)
float, intent(in) :: s
volume_cube_float = s**3
end function volume_cube_Float
integer function volume_cube_Double(s)
DOUBLE, intent(in) :: s
volume_cube_Double = s**3
end function volume_cube_Double
end module Pablo_Dali
then the code:
PROGRAM Cube_Volume
USE Pablo_Dali
IMPLICIT NONE
INTEGER :: I_Side, I_Volume
FLOAT :: F_Side, F_Volume
DOUBLE :: D_Side, D_Volume
I_Side = 1
F_Side = 1.0E0
D_Side = 1.0D0
WRITE(*,*)'[INT] ',I_Side,' cubed=', volume_cube(I_Side)
WRITE(*,*)'[FLOAT] ',F_Side,' cubed=', volume_cube(F_Side)
WRITE(*,*)'[DOUBLE] ',D_Side,' cubed=', volume_cube(D_Side)
END PROGRAM Cube_Volume
I want to combine C++ and Fortran together. My Fortran code will use a C++ function and C++ function changes variables of Fortran and sends them back. The C++ function is built with other C++ codes, e.g. the C++ function will use some sub-function in other .cpp file. I make the Fortran code with ifort and I added that C++ function as one object file, test.o in my Fortran makefile. I also put every needed C++ .o file(support test.o) in makefile. It shows the error
#6633, "The type of the actual argument differs from the type of the dummy argument".
Here is the code.
Fortran code
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE
implicit double precision(a-h,o-z),integer(i-n)
Interface
integer (C_INT) function SolveBIE_(x, y, aa, m) BIND(C, NAME='SolveBIE_')
use, intrinsic :: ISO_C_BINDING
implicit none
type (C_PTR), value :: x
type (C_PTR), value :: y
type (C_PTR), value :: aa
integer (C_INT), value :: m
end function SolveBIE_
end Interface
integer (C_INT) :: m
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: x
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: y
real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: aa
ALLOCATE(x(0:MAXLEN,MAXINTERFACES))
ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))
My Fortran code run
mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m)
Using the C++ code and where the error is from, on x, y, aa
I use x(1,1) instead of x, because if using x, then there is another error
#6634,"the shape matching rules of actual arguments and dummy arguments have been violated"`
I don't understand why it should be x(1,1). Why is this working, not x?
My C++ code
#ifdef __cplusplus
extern "C" {
#endif
int solveBIE_(double *ini_bdry_x, double *ini_bdry_y, double *ini_bdry_um, int *fM)
{
double(*bdry_node)[2] = new double[M1][2];
for (int k = 0; k < M; k++) {
bdry_node[k+1][0] = ini_bdry_x[k+1];
bdry_node[k+1][1] = ini_bdry_y[k+1];
bdry_theta[k+1] = Atan(ini_bdry_x[k+1], ini_bdry_y[k+1]);}
... some functions in other .cpp file
The way your interface is written, you have to construct a C_PTR to array x and pass that as the first argument:
use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE, C_PTR, C_LOC
! ...
type(C_PTR) PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx, PTRy, PTRaa, m)
As shown above, you would have to fix the next two arguments as well. But you need to rewrite the interface for argument fM because as matters stand, Fortran will pass an integer by value whereas C++ is expecting a pointer. Given that, I would rewrite the interface completely, using the names given for the arguments in the C++ function and passing everything by reference. Names for dummy arguments are potentially visible in Fortran, so it's useful for them to be meaningful. In the following I assume that fM points to a scalar in the callee:
Interface
function SolveBIE_(ini_bdry_x, ini_bdry_y, ini_bdry_um, fM) &
BIND(C, NAME='SolveBIE_')
import
implicit none
integer(C_INT) SolveBIE_
real(C_DOUBLE) :: ini_bdry_x(*)
real(C_DOUBLE) :: ini_bdry_y(*)
real(C_DOUBLE) :: ini_bdry_um(*)
integer (C_INT) :: fM
end function SolveBIE_
end Interface
Then later on you can invoke it more or less normally as
mm = SolveBIE_(x,y,aa,m)
Note that x(1,1) was wrong because LBOUND(x,1) = 0, not 1!
I am trying to pass an array from C/C++ into a Fortran 2003 module and get the calculated values back into C/C++. I've been able to pass and return single values (scalars) just fine, but getting an array back and forth is proving difficult. I've found many threads on scalar values and I've been successful at making those work.
I've modeled my array based functions after my working scalar functions.
I am using gcc/gfortran.
Here's the Fortran module (ConvertUnitsLib.f03).
module ConvertUnitsLib
use :: iso_c_binding ! for C/C++ interop
real(c_double), bind(c) :: degF, degC
public DegCtoF
contains
!
! Convert temperature degrees Celsius Fahrenheit
!
real(kind = c_double) function DegCtoF(degC) result(degF) &
& bind(c, name = "DegCtoF")
real(c_double), intent(in), dimension(:) :: degC
real(c_double), dimension(size(degC)) :: degF
do i = 1, size(degC)
degF(i) = ( degC(i) * 1.8 ) + 32
end do
end function DegCtoF
! End of module
end module ConvertUnitsLib
And the C/C++, (CFort.cpp)
#include <stdio.h>
#ifdef __cplusplus
extern"C" {
#endif
double DegCtoF(double *[]);
#ifdef __cplusplus
}
#endif
/**********************************************************************/
int main(int argc, char *argv[])
{
printf("C/C++ and Fortran together!\n");
double DegreesC[2] = {32, 64};
double DegreesF[2];
DegreesF = DegCtoF(&DegreesC);
printf("%3.1f [C] = %3.1f [F]\n", DegreesC, DegreesF );
return 0;
}
And last but not least, the Makefile
# C++ directives
CC=g++
CFLAGS=-std=c++11
# Fortran directives
FC=gfortran
FFLAGS=-std=f2003
all: clean
$(FC) $(FFLAGS) -c -fcheck=all ConvertUnitsLib.f03
$(CC) $(CFLAGS) -c CFort.cpp
$(FC) $(FFLAGS) ConvertUnitsLib.o CFort.o -o convert
clean:
rm -f *.o
rm -f *.mod
Under the rules of current Fortran (Fortran 2008, but this is the same for when C interoperability was introduced in Fortran 2003), a Fortran procedure is not interoperable with C if it has an assumed shape dummy argument (other restrictions also apply). In your code degC, the dummy argument in the function DegCtoF, declared as
real(c_double), intent(in), dimension(:) :: degC
is such a thing.
So, under F2003 you cannot have such an interoperable function. Which is where things get tricky.
In the proposed draft for F2015 (based on the ISO TS29113 Further Interoperability of Fortran with C) such a thing is interoperable. And this syntax is (I think) supported by recent versions of gcc which is why the code is not rejected by gfortran.
(TS) Standardized interoperation with such a procedure with an assumed shape argument, however, requires using the C descriptor described in ISO_Fortran_binding.h on the C side which is not implemented in gcc. To do such interaction instead requires understanding the gcc array descriptor directly.
But you're in luck. In your case you don't really need to use an assumed shape dummy argument: you can use an explicit shape dummy argument and such interoperation is part of F2003. All you need to do is pass the size of the array.
Either way, an interoperable function must return a scalar result, so you'll also want to move to a subroutine, as given in the answer by innoSPG.
Finally, I'll mention your use of
real(c_double), bind(c) :: degF, degC
in the module.
These are interoperable global variables (through linkage association). You don't reference these variables in the Fortran code: the dummy and the function result are not these things.
In this simple case from the above, and the other answer, one will happily have a subroutine like
subroutine DegCtoF(n, degC, degF) bind(c,name='DegCtoF')
...
end subroutine
but this is perhaps a good opportunity to describe the use of the C descriptor from ISO_Fortran_binding.h. Note, though, that in the immediate term gfortran does not support this approach.
Consider the Fortran source
subroutine DegCtoF(degC, degF) bind(c,name='DegCtoF')
use, intrinsic :: iso_c_binding, only : c_double
implicit none
real(c_double), intent(in), dimension(:) :: degC
real(c_double), intent(out), dimension(*) :: degF
degF(1:SIZE(degC)) = degC*1.8+32
end subroutine DegCtoF
(for simplicity I'm going to assume that the memory management of degF is done all on the C side - naturally one could extend beyond the assumed size array). For this subroutine to be interoperable the argument corresponding to degC must be a pointer to CFI_cdesc_t.
Take the C code (with size magic numbers)
#include "ISO_Fortran_binding.h"
#include <stdio.h>
void DegCtoF(CFI_cdesc_t*, double*);
int main(int argc, char *argv[])
{
printf("C and Fortran together!\n");
CFI_CDESC_T(1) DegreesC_Fdesc;
CFI_index_t extent[1] = {2};
CFI_rank_t rank = 1;
double DegreesC[2] = {32, 64};
double DegreesF[2];
CFI_establish((CFI_cdesc_t*)&DegreesC_Fdesc, &DegreesC, CFI_attribute_other,
CFI_type_double, 2*sizeof(double), rank, extent);
DegCtoF((CFI_cdesc_t*)&DegreesC_Fdesc, DegreesF);
printf("%3.1f [C] = %3.1f [F]\n", DegreesC[0], DegreesF[0] );
printf("%3.1f [C] = %3.1f [F]\n", DegreesC[1], DegreesF[1] );
return 0;
}
Here CFI_establish establishes a suitable C descriptor DegreesC_Fdesc which can correspond to the assumed shape Fortran dummy argument. Inside the Fortran subroutine there is no problem at all assessing the size of the incoming array.
Before francescalus confirms it, I was going to say that from what I know that was a little bit old, the interoperability does not permit what you are trying to do with arrays.
In addition, some good habits are always critical when coding. For example using implicit none in fortran to force the declaration of all variables before they are used. The use of named constant when the language permits it, for example the 2 that you are using as array size in fortran.
Below is a modified version of your code that should do something like what you want to achieve.
//Fortran
module ConvertUnitsLib
use :: iso_c_binding ! for C/C++ interop
!real(c_double), bind(c) :: degF, degC
implicit none
public DegCtoF
contains
!
! Convert temperature degrees Celsius Fahrenheit
!
subroutine DegCtoF(degC, degF, n)&
bind(c, name = "DegCtoF")
integer, intent(in) :: n
real(c_double), intent(in), dimension(n) :: degC
real(c_double), intent(out), dimension(n) :: degF
integer :: i
do i = 1, n
degF(i) = ( degC(i) * 1.8 ) + 32
end do
end subroutine DegCtoF
// C++
#include <stdio.h>
#ifdef __cplusplus
extern"C" {
#endif
double DegCtoF(double [], double [], const int *);
#ifdef __cplusplus
}
#endif
/**********************************************************************/
int main(int argc, char *argv[])
{
const int N = 2;
printf("C/C++ and Fortran together!\n");
double DegreesC[N] = {32, 64};
double DegreesF[N];
DegCtoF(DegreesC, DegreesF, &N);
for(int i = 0; i<N; i++){
printf("%d : %3.1f [C] = %3.1f [F]\n", i, DegreesC[i], DegreesF[i] );
}
return 0;
}
The Fortran intrinsic function transfer can be used to covert a derived type into a real or integer array. This is potentially very useful when working in legacy systems which relies on arrays of primitive types (integer, real etc.) for persistence.
The code below runs at least on ifort and gfortran and converts a simple derived type example to an integer array (updated with solution):
program main
implicit none
integer, parameter :: int_mem_size = storage_size(1)
type subtype
integer a
double precision b
end type subtype
type :: mytype
integer :: foo
double precision :: bar
type(subtype) :: some_type
end type
type(mytype) :: my_var
type(subtype) :: my_subtype
! Old version: integer :: x(30)
integer, allocatable :: x(:)
integer :: mem_size
!Allocate array with required size
mem_size = storage_size(my_var)
allocate(x(mem_size/int_mem_size))
my_subtype%a = 1
my_subtype%b = 2.7
my_var%foo = 42
my_var%bar = 3.14
my_var%some_type = my_subtype
write(*,*) "transfering..."
x = transfer(my_var, x)
write(*,*) "Integer transformation:", x
end program main
On my PC, this is the output (this result is at least platform dependent):
transfering...
Integer transformation: 42 0 1610612736 1074339512
999 0 -1610612736 1074108825
My problem is that I have "guessed" that a 30 element long integer array is large enough to store this data structure. Is there a way I can determine how large the array needs to be to store the whole data structure?
If you have a Fortran 2008 compliant compiler, or one that is compliant enough, you will find the intrinsic function storage_size which returns the number of bits used to store its argument. Failing that most compilers that I am familiar with implement a non-standard function to do this; the Intel Fortran compiler has a function called sizeof which returns the number of bytes required to store its argument.