I found a small helper subroutine from a larger legacy codebase that computes some statistics for a vector and have compiled it alone and am trying to call it from Julia (0.6.2) for practice.
To begin, I have found some forum posts and discourse threads, but I wanted to double check since the language is developing quickly and some may be using outdated syntax like this one. Additionally, I am using Windows and many of the forum posts I came across reference .so files, which to my understanding is for UNIX systems, not Windows?
The Fortran code I am referencing (called meansd.f) in its entirety is:
SUBROUTINE MEANSD (A,N,ABAR,VAR,STD)
IMPLICIT NONE
C COMPUTE THE MEAN AND STANDARD DEVIATION OF A REAL VECTOR.
C PARAMETERS:
C A: REAL VECTOR TO COMPUTE MEAN AND STANDARD DEVIATION OVER.
C N: LENGTH OF A.
C ABAR: COMPUTED MEAN OF A.
C VAR: VARIANCE OF A.
C STD: COMPUTED STANDARD DEVIATION OF A.
C
REAL A(N)
INTEGER I,N
DOUBLE PRECISION APX, ABAR, VAR, STD, SUM, SUMSQ, DN, Z
C
DN=N
APX=0D0
DO 30 I=1,N
APX=APX+A(I)
30 CONTINUE
APX=APX/DN
SUM=0D0
SUMSQ=0D0
DO 40 I=1,N
Z=A(I)-APX
SUM=SUM+Z
SUMSQ=SUMSQ+Z*Z
40 CONTINUE
ABAR=SUM/DN
VAR=(SUMSQ-(SUM*ABAR))/(DN-1)
STD=DSQRT(VAR)
ABAR=ABAR+APX
RETURN
END
I have compiled this using gcc
gcc (x86_64-posix-seh-rev1, Built by MinGW-W64 project) 7.2.0
largely following this question, which completes with no errors:
gfortran -c meansd.f
gfortran -shared -fPIC meansd.o -o meansd.dll
when I test with Libdl
, everything seems to return fine and I get returned a pointer
path=joinpath(pwd(),"meansd.dll")
dl=Libdl.dlopen(path)
and then I try to build my ccall
function as:
a_ref=Ref{Array{Float64,1}}([5.0,5.0,5.0,5.0,5.0])
i_ref=Ref{Int64}(1)
n_ref=Ref{Int64}(length([5.0,5.0,5.0,5.0,5.0]))
apx_ref=Ref{Float64}(0)
abar_ref=Ref{Float64}(0)
var_ref=Ref{Float64}(0)
std_ref=Ref{Float64}(0)
sum_ref=Ref{Float64}(0)
sumsq_ref=Ref{Float64}(0)
dn_ref=Ref{Float64}(0)
z_ref=Ref{Float64}(0)
ccall((:meansd_,"meansd.dll"),Void,(
Ref{Array{Float64,1}},#A
Ref{Int64}, #I
Ref{Int64}, #N
Ref{Float64}, #APX #I think I have to pass these too?
Ref{Float64}, #ABAR
Ref{Float64}, #VAR
Ref{Float64}, #STD
Ref{Float64}, #SUM
Ref{Float64}, #SUMSQ
Ref{Float64}, #DN
Ref{Float64}, #Z
),a_ref,i_ref,n_ref,apx_ref,
abar_ref,var_ref,std_ref,sum_ref,sumsq_ref,dn_ref,z_ref)
This completes which is as far as I have gotten, but abar_ref
is returned as NaN
. I then made a Float/Int 32 version as well, which completes but abar_ref
is returned as 0.0
. I thought I should be using 64 bit, since I compiled with 64 bit gfortran.
I think I am messing up on how to pass the array, but I have tried as many different approached I could think of with no success.
I am also confused as to when to use Julia types vs the ccall
types (Float32
vs Cint
?). I have seen examples of both scattered among the web, but if I am reading correctly, there are underlying convert statements built in behind the scenes at this point which handle that?