Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

Biology grows on you.


devel / comp.lang.c++ / Re: Problem with calling C++ from Fortran

Re: Problem with calling C++ from Fortran

<f1b6f8e1-fa16-4fb7-b4b2-883788d098fdn@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=1470&group=comp.lang.c%2B%2B#1470

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:ad4:4b6a:0:b0:63d:30b8:ff8b with SMTP id m10-20020ad44b6a000000b0063d30b8ff8bmr268889qvx.13.1694529175123;
Tue, 12 Sep 2023 07:32:55 -0700 (PDT)
X-Received: by 2002:a17:90a:778a:b0:274:920:a44c with SMTP id
v10-20020a17090a778a00b002740920a44cmr1825174pjk.3.1694529174503; Tue, 12 Sep
2023 07:32:54 -0700 (PDT)
Path: i2pn2.org!i2pn.org!usenet.blueworldhosting.com!diablo1.usenet.blueworldhosting.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Tue, 12 Sep 2023 07:32:53 -0700 (PDT)
In-Reply-To: <87a5trplua.fsf@bsb.me.uk>
Injection-Info: google-groups.googlegroups.com; posting-host=199.203.251.52; posting-account=ow8VOgoAAAAfiGNvoH__Y4ADRwQF1hZW
NNTP-Posting-Host: 199.203.251.52
References: <udhbs9$e5d$1@dont-email.me> <udhcaj$j8l$1@dont-email.me>
<udkdu9$itm4$1@dont-email.me> <87o7iajh8b.fsf@bsb.me.uk> <udmvg7$11r4u$1@dont-email.me>
<87cyyoqoka.fsf@bsb.me.uk> <2ccb965a-8d31-48af-97ad-2d96daa4862dn@googlegroups.com>
<87a5trplua.fsf@bsb.me.uk>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <f1b6f8e1-fa16-4fb7-b4b2-883788d098fdn@googlegroups.com>
Subject: Re: Problem with calling C++ from Fortran
From: already5chosen@yahoo.com (Michael S)
Injection-Date: Tue, 12 Sep 2023 14:32:55 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 11124
 by: Michael S - Tue, 12 Sep 2023 14:32 UTC

On Tuesday, September 12, 2023 at 4:23:09 PM UTC+3, Ben Bacarisse wrote:
> Michael S <already...@yahoo.com> writes:
>
> > On Tuesday, September 12, 2023 at 2:26:49 AM UTC+3, Ben Bacarisse wrote:
> >> db <dieterh...@gmail.com> writes:
> >>
> >> > On 10.09.2023 15.22, Ben Bacarisse wrote:
> >> >> db <dieterh...@gmail.com> writes:
> >> >>
> >> >>> On 09.09.2023 11.02, Mut...@dastardlyhq.com wrote:
> >> >>>> On Sat, 9 Sep 2023 10:54:33 +0200
> >> >>>> db <dieterh...@gmail.com> wrote:
> >> >>>>> but now it says that C-double doesn't exist.
> >> >>>>>
> >> >>>>> Any ideas?
> >> >>>> C++ mangles function names so that the name you give the function isn't
> >> >>>> the
> >> >>>> name the dynamic loader sees in the binary. You need to put this around whatever
> >> >>>> function you want to call from Fortran so it has C style linkage which means
> >> >>>> the name remains the same:
> >> >>>> extern "C" {
> >> >>>> void calledFromFortran()
> >> >>>> {
> >> >>>> :
> >> >>>> }
> >> >>>> }
> >> >>>>
> >> >>> Where should this go in the code? I added it at the end as is,
> >> >>> and now I get this:
> >> >>>
> >> >>> ~/ownlib90/tests> ./jbandtest
> >> >>> jband.cpp:88:1: error: expected initializer before 'extern'
> >> >>> 88 | extern "C" {
> >> >>> | ^~~~~~
> >> >>> jband.cpp:96:1: error: expected unqualified-id before '{' token
> >> >>> 96 | {
> >> >>> | ^
> >> >>> jband.cpp: In function 'void calledFromFortran()':
> >> >>> jband.cpp:350:9: error: expected primary-expression before ':' token
> >> >>> 350 | :
> >> >>> ...
> >> >> You are giving people very little to go on. There's an unknown command
> >> >> (./jbandtest) the gives some errors where only one line of code can be
> >> >> seen.
> >> >> Can you produce a cut-down version to the program that shows the same
> >> >> error -- mimimal example of the C++ and of the Fortran that should
> >> >> calls it but which fails? That would mean you could post the code.
> >> >> If that is not possible, can you link to the source so those who know
> >> >> both C++ and Fortran can take a proper look?
> >> >
> >> > I put the C++ function here: www.dieterbritz.dk/jband.cpp
> >> > After getting errors about the extern lines, whch I had
> >> > added at the end, I shifted it to near the start:
> >> >
> >> > #include <iostream>
> >> > #include <fstream>
> >> > #include <iomanip>
> >> > #include "math.h"
> >> >
> >> > using namespace std;
> >> >
> >> > extern "C" {
> >> >
> >> > void calledFromFortran()
> >> > {
> >> > :
> >> > }
> >> >
> >> > }
> >> Remove them all. You have two options. One: correct the C++. To do
> >> this put this, and only this,
> >>
> >> extern "C" {
> >> const long double iband(const long double tbar);
> >> }
> >>
> >> just after the #include lines. This is perfect (the first const is a
> >> meaningless word here and the compiler may warn you about that) but it
> >> will do.
> >>
> >> Next replace
> >>
> >> #include "math.h"
> >>
> >> with
> >>
> >> #include <math.h>
> >>
> >> I'd also remove the two unnecessary #include lines (for iomanip and
> >> fstream). All of these are "tidying up". Only the extern "C" part I
> >> gave corrects an actual mistake.
> >>
> >> The second option is the turn the code in C which links directly with
> >> Fortran. The only C++ used by the code is one "cout << " line (not a
> >> good way to report an error, but that's not important right now) and a
> >> setting for pi that is not a compile-time constant (4*atanl(1)) written
> >> in a more fussy way.
> >>
> >> To convert to C, copy the file to jband.c (rather than .cpp) and replce
> >> the declaration for pi. Given the code is littered with explicit 21
> >> digits decimals (a little more than the precision of C's usualy long
> >> double type) I would just write
> >>
> >> static const long double pi = 3.14159265358979323846L;
> >>
> >> Now replace the cout line with
> >>
> >> fputs("\nError in stredges::iband(): tbar must be > 0", stderr);
> >>
> >> This writes the message to the error stream and put only these two
> >> include lines at the top:
> >>
> >> #include <math.h>
> >> #include <stdio.h>
> >>
> >> Now the file is C code.
> >>
> >> Frankly, this is the way I'd go, since linking C is just that bit
> >> simpler than linking C++. But if the code is going to become fully
> >> fledged (and complex) C++, obviously use my first option.
> >> > I still get errors pertaining to these lines. But after adding
> >> > the -c to the two compilation lines in the script, these are
> >> > now the only errors. I think I am getting closer. The errors
> >> > are now
> >> Yes, you must compile it like this:
> >>
> >> g++ -c jband.cpp (for C++ code)
> >> gcc -c jband.c (for C code)
> >>
> >> You don't need any -o but you could add in lots of warnings like
> >>
> >> gcc -Wall -Wextra -c jband.c
> >> > jband.cpp: In function 'void calledFromFortran()':
> >> > jband.cpp:12:9: error: expected primary-expression before ':' token
> >> > 12 | :
> >> > | ^
> >> > jband.cpp: At global scope:
> >> > jband.cpp:96:1: error: expected initializer before 'extern'
> >> > 96 | extern "C" {
> >> > | ^~~~~~
> >> > jband.cpp:104:1: error: expected unqualified-id before '{' token
> >> > 104 | {
> >> > | ^
> >> > jbandtest.f90:28:14:
> >> >
> >> > 28 | FORTJBAND = JBAND (tbar)
> >> > | 1
> >> > Error: Type mismatch in argument 'tbar' at (1); passed REAL(16) to REAL(10)
> >> >
> >> > The last error will go away together with the others.
> >> Michael S has given you one way to go for that. My comments were going
> >> to be more general. You have several ways of specifying the types, and
> >> I could not tell if you really wanted all of them. In general, I would
> >> define the Fortran types from the C ones (since those are the types you
> >> need for the call and return) and leave it at that.
> >>
> >> But the big one is that the Fortran code seems to think the function is
> >> called jband, when in fact it's called iband.
> >>
> >> I went for this:
> >>
> >> module STUFF
> >> use iso_c_binding
> >> integer, parameter :: qud=real(c_long_double)
> >> end module STUFF
> >> program JBAND_TEST
> >> use STUFF; implicit none
> >> real(qud) :: tbar, curr, FORTJBAND
> >> do
> >> read *, tbar
> >> if (tbar < 0) exit
> >> curr = FORTJBAND (tbar)
> >> print '(" curr =", f10.4)', curr
> >> enddo
> >> end program JBAND_TEST
> >>
> >> function FORTJBAND (tbar)
> >> use STUFF; implicit none
> >> interface
> >> function IBAND (tbar) bind(c)
> >> use STUFF
> >> real(qud), VALUE :: tbar
> >> real(qud) :: IBAND
> >> end function iband
> >> end interface
> >
> > I think, you are taking chances here. Even if it happens to work
> > on x86-64 Linux, it can fail on some other target where calling
> > conventions for long double return value in 'C' differ from those
> > of Fortran. The method shown in one of my previous posts
> > appear more robust:
> >
> > interface
> > real(c_long_double) function IBAND (tbar) bind(c)
> > import c_long_double
> > real(c_long_double), value :: tbar
> > end function IBAND
> I think I see -- keep the C-related types in the smallest interface? I
> didn't study your example, but the OP renamed the C function and gave
> the resulting Fortran function a native Fortran type. Is that what you
> advise?
>
> The OP should have taken your Fortran and applied my C++ edits. Maybe
> they took my Fortran and it did not work on Windows. That would be a
> shame.
> >> BTW, you said the C++ was written by a C++ expert. I don't think it
> >> was!
> >
> > With no relationships to C, C++ or Fortran, I don't like the way they
> > evaluate their polynomials from numerical perspective . But I assume
> > that algorithm was copied 'as is' from 40 y.o. book so it's not a
> > fault of C++ programmer.
> I was just remarking on the C++ itself which has some 'non-expert'
> attributes.
> > Despite my disliking, their method is good enough to achieve their modest
> > specified goal for relative accuracy: of 14-15 significant digits.
> > With smarter method the same or better accuracy can be achieved using
> > standard 'double" arithmetic (IEEE-754 binary64) thus making the routine
> > portable to platforms that have no support for extended precision
> > math.
> Interesting. I don't know the function being evaluated at all.
>

I don't know it either. But I had drawn the graphs and looked at
coefficients in two ranges where precision is worst: [0.0081: 0.0158] and
[0.0158:0.0631].
A simple affine transform of the polynomial could either improve precision
of result by 4 orders of magnitude or reduce needs for precision of arithmetic
by 3 orders of magnitude while still somewhat improving the precision of result.
I'd guess, more advanced techniques can improve it further in both dimensions,
but low hanging fruits first.

> --
> Ben.

SubjectRepliesAuthor
o Problem with calling C++ from Fortran

By: db on Sat, 9 Sep 2023

31db
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor