I'd like to match the following c++ syntax to fortran:
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <math.h>
int main() {
std::vector<double> four_vector;
for (double i=0.0; i<4.0; i++)
four_vector.push_back(sqrt(i));
std::cout.precision(16);
std::copy(four_vector.begin(), four_vector.end(),
std::ostream_iterator<double>(std::cout, "\n"));
return 0;
}
// g++ -o vector2 vector2.cpp
// vector2 >text55.txt 2>text56.txt
This creates and prints a four_vector with the root of the i-th entry as
output. Text55.txt reads:
0
1
1.414213562373095
1.732050807568877
, so what to do with zero and one is going to be an issue.
I would think that analogous fortran prog should have selected_real_kind set
with the same precision: 16. They got thirteen anyways. Referent source
could be utab's source on this:
> subroutine vectorProduct(res,vec1,vec2,n)
> implicit none
> integer ::n ! dimension of the
> vector
> real, dimension(:) ::vec1,vec2 ! dimension of the vectors are
> real res ! result of the
> operation
> res=dot_product(vec1,vec2) ! dot_product is used to compute the
> ! result
> end subroutine vectorProduct
This has next step in this process, which is to create another vector of the
same size and pass it to another syntax for the figuring. Neither of the
above is my own source; the former is from larry in c.l.c++ and the latter
is homegrown and elsethread.
I'd like to get this program nailed in time for the release of gfortran
4.3.0, and use it as a hello world to show capabilities of the gnu compiler
collection. My contribution is the goocher:
// g++ -o vector2 vector2.cpp
// vector2 >text55.txt 2>text56.txt
These are the most labor-saving comments I've ever made. For windows users
of open source distros, you just might like it.
Anyways, to the question. Tim Prince thought that utab's subroutine went
out of its way tomake something hard. I saw no source posting after this
serious criticism. How does one emulate the above program in fortran, with
an eye to the intention to create another vector of the same size, pass it
to a function that calculates their inner product and outputs to stdout?
Grateful for your thoughtful comment.
--
Gerry Ford
"Er hat sich georgiert." Der Spiegel, 2008, sich auf Chimpy Eins komma null
beziehend.
"Gerry Ford" <inv...@invalid.net> wrote in message
news:1203217...@news.newsgroups.com...
> I'd like to match the following c++ syntax to fortran:
>
> #include <vector>
> #include <algorithm>
> #include <iterator>
> #include <iostream>
> #include <math.h>
>
> int main() {
> std::vector<double> four_vector;
>
> for (double i=0.0; i<4.0; i++)
> four_vector.push_back(sqrt(i));
>
>
> std::cout.precision(16);
> std::copy(four_vector.begin(), four_vector.end(),
> std::ostream_iterator<double>(std::cout, "\n"));
> return 0;
> }
program vector1
implicit none
integer index, i
integer, parameter :: some_kind_number = selected_real_kind (p=16)
real (kind = some_kind_number), dimension(4):: vec_a, vec_b
index = 4
do i = 1, index
vec_a(i)= i**.5
vec_b(i)= (-1)*(i**2)
end do
write (*,*) vec_a, vec_b
end program vector1
! end source begin comment
I'm defining dp here differently than I usually do, thinking that I'm going
to pass an appropriate p eventually. Is (p=16) a keyword argument?
So I don't have the usual parameter dp defined here. So what would you
append to scalars so that your compiler doesn't think that there isn't
undesired mixed precision?
I could not get this point, could you be a bit more specific on that?
Rgds,
selected_real_kind is orthogonal to std::cout.precision; the latter is
more like a format descriptor, except that the standard iostreams are
designed to be used a bit differently from Fortran formatted writes.
Anyway, the analogous Fortran code would be something like:
PROGRAM Vector_Sqrt
IMPLICIT NONE
! I'm going to assume that Fortran double is equivalent to C/C++ double.
INTEGER, PARAMETER :: dp = KIND(0.0d0)
REAL(DP) :: four_vector(4)
INTEGER :: i
DO i = 1, 4
four_vector(i) = SQRT(REAL(i, DP))
ENDDO
WRITE(*,'(4F19.16)') four_vector
END
(If you really want to, you can write Fortran code to do something like
std::vector.push_back(); I've actually done so before. It's tedious and
mechanical, so I think it's beyond the scope of this discussion.)
>> subroutine vectorProduct(res,vec1,vec2,n)
>> implicit none
>> integer ::n ! dimension of the
>> vector
>> real, dimension(:) ::vec1,vec2 ! dimension of the vectors are
>> real res ! result of the
>> operation
>> res=dot_product(vec1,vec2) ! dot_product is used to compute the
>> ! result
>> end subroutine vectorProduct
From here forward, I'm not clear on what you want. Once we got utab's
code into agreement, the only point of complication that arose was when
I/O was introduced into the fortran side; when that happens, if you
don't like the program with gfortran, you have to make sure you link
against the appropriate libraries (i.e. libgfortran and libgfortranbegin).
I never saw an update of your source that would reflect any of the forum
criticisms.
This is the latest version of my c++ program to match:
// vector3.cpp contributor: Jim Langston
#include <cmath>
#include <vector>
#include <iostream>
#include <iterator>
double dot_product (const std::vector<double>& vec_a, const
std::vector<double>& vec_b)
{
if ( vec_a.size() != vec_b.size() )
{
std::cerr << "Vectors for dot product are not same size!\n";
return 0.0;
}
double sum = 0;
for ( std::size_t i = 0; i < vec_a.size(); ++i )
{
sum += vec_a[i] * vec_b[i];
}
return std::pow(sum, .5);
}
// Following prototype is not needed in this program since
// the definition is above, but would be used in another
// source file without the previous definition.
double dot_product (const std::vector<double>& vec_a, const
std::vector<double>& vec_b);
int main()
{
std::vector<double> vec_a;
std::vector<double> vec_b;
for ( int i = 0; i < 4; ++i )
{
vec_a.push_back( std::sqrt( static_cast<double>( i )) );
vec_b.push_back( (-1.0) *i * i );
}
std::cout.precision(16);
std::copy(vec_a.begin(), vec_a.end(),
std::ostream_iterator<double>(std::cout, "\n"));
std::copy(vec_b.begin(), vec_b.end(),
std::ostream_iterator<double>(std::cout, "\n"));
std::cout << "Dot Product: " << dot_product(vec_a, vec_b) << "\n";
return 0;
}
// g++ -o vector3 vector3.cpp -v >text57.txt 2>text58.txt
So we have our c++ function for the dot-product. That the output needs help
to reflect a negative value is fortunate: I'll ask the friendly folks in
c.l.c++ to fix that and help me herd it into an external function as well.
I have better information from the -v switch, but it's a mixed bag, as
text58 shows:
Built by Equation Solution (http://www.Equation.com).
Using built-in specs.
Target: i386-pc-mingw32
Configured with:
../gcc-4.2.3-mingw/configure --host=i386-pc-mingw32 --build=x86_64-unknown-linux-gnu
--target=i386-pc-mingw32 --prefix=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3
--with-gcc --with-gnu-ld --with-gnu-as --disable-shared --disable-nls --disable-tls
--with-gmp=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gmp --with-mpfr=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/mpfr
--enable-languages=c,c++,fortran --with-sysroot=/home/gfortran/gcc-home/binary/mingw32/cross/x86_32/gcc/4.2.3
--enable-threads=win32 --enable-libgomp --disable-win32-registry
Thread model: win32
gcc version 4.2.3
c:/gcc/bin/../libexec/gcc/i386-pc-mingw32/4.2.3/cc1plus.exe -quiet -v -iprefix
c:\gcc\bin\../lib/gcc/i386-pc-mingw32/4.2.3/ vector3.cpp -quiet -dumpbase
vector3.cpp -mtune=i386 -auxbase vector3 -version -o
C:\DOCUME~1\dan\LOCALS~1\Temp/ccSBH2Z3.s
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3/include/c++/4.2.3"
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3/include/c++/4.2.3/i386-pc-mingw32"
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3/include/c++/4.2.3/backward"
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/cross/x86_32/gcc/4.2.3/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3/lib/gcc/i386-pc-mingw32/4.2.3/../../../../include"
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3/lib/gcc/i386-pc-mingw32/4.2.3/include"
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.2.3/i386-pc-mingw32/include"
ignoring nonexistent directory
"/home/gfortran/gcc-home/binary/mingw32/cross/x86_32/gcc/4.2.3/mingw/include"
#include "..." search starts here:
#include <...> search starts here:
C:/gcc/include
c:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../../../include/c++/4.2.3
c:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../../../include/c++/4.2.3/i386-pc-mingw32 c:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../../../include/c++/4.2.3/backward c:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/include c:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../../../i386-pc-mingw32/includeEnd of search list.GNU C++ version 4.2.3 (i386-pc-mingw32) compiled by GNU C version 4.2.3.GGC heuristics: --param ggc-min-expand=99 --param ggc-min-heapsize=131006Compiler executable checksum: 7d1ae633d2d0a50743a002fa1f809f44 c:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../../../i386-pc-mingw32/bin/as.exe -o C:\DOCUME~1\dan\LOCALS~1\Temp/ccFprGbf.oC:\DOCUME~1\dan\LOCALS~1\Temp/ccSBH2Z3.s c:/gcc/bin/../libexec/gcc/i386-pc-mingw32/4.2.3/collect2.exe --sysroot=/home/gfortran/gcc-home/binary/mingw32/cross/x86_32/gcc/4.2.3 -Bdynamic -s -ovector3.exeC:/gcc/i386-pc-mingw32/lib/crt2.o -Lc:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3 -Lc:/gcc/bin/../lib/gcc -LC:/gcc/i386-pc-mingw32/lib -Lc:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../../../i386-pc-mingw32/lib -Lc:/gcc/bin/../lib/gcc/i386-pc-mingw32/4.2.3/../../..C:\DOCUME~1\dan\LOCALS~1\Temp/ccFprGbf.o -lstdc++ -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lshell32 -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt# end text58.txtYikes! My tendency would be to yell at someone who brought me somethingthat looks like this. One thing I think it shows is a drawback to havingtwo open source distros: the linker seems to be confused. It's rumored thatthe information for which libraries to include is above in order to use thisc++ prog intersyntactically. I don't see it.--Gerry Ford"Er hat sich georgiert." Der Spiegel, 2008, sich auf Chimpy Eins komma nullbeziehend.
I'm also unclear what is the goal here. I think I have already (and Craig
as well) explained in detail what needs to be done to compile and link
mixed-code programs. For example, mixed C and Fortran (with C main) is:
$ cat a.f90
real(8) function prod (x, y, n)
real(8), intent(in) :: x(n), y(n)
integer, intent(in) :: n
prod = dot_product (x,y)
end function prod
$ cat b.c
#include <stdio.h>
#include <math.h>
int main (void)
{
extern double prod_ (double *a, double *b, int *n);
double a[10], b[10], p = 0;
int i;
for (i = 0; i < 10; i++)
a[i] = sqrt((double) i), b[i] = -1. * i * i;
for (i = 0; i < 10; i++)
p += a[i] * b[i];
i = 10;
printf ("%lg %lg\n", p, prod_ (a, b, &i));
return 0;
}
$ gcc -c b.c && gfortran -c a.f90 && gfortran b.o a.o && ./a.out
-751.99 -751.99
In the linking stage ("gfortran b.o a.o"), "gfortran" can be replaced by "gcc"
if you add "-lgfortran -lm":
$ gcc -c b.c && gfortran -c a.f90 && gcc a.o b.o -lgfortran -lm && ./a.out
-751.99 -751.99
If the main program is in Fortran, it's as easy:
$ cat u.f90
program demo
real(kind=8), external :: sqrt_from_c
real(kind=8) :: x
x = 2
print *, sqrt(x), sqrt_from_c(x)
end program demo
$ cat v.c
#include <math.h>
double sqrt_from_c_ (double *x)
{
return sqrt(*x);
}
$ gcc -c v.c && gfortran -c u.f90 && gfortran u.o v.o && ./a.out
1.41421356237310 1.41421356237310
Once again, you can use "gcc" instead of "gfortran" in the linking stage, but
that requires to add "-lgfortranbegin -lgfortran -lm":
$ gcc -c v.c && gfortran -c u.f90 && gcc u.o v.o -lgfortranbegin -lgfortran -lm && ./a.out
1.41421356237310 1.41421356237310
You can do the same things with C++ code, just (a) use g++ instead of c++
and (b) use the second kind of linking command, ie with "g++ [...]
[-lgfortranbegin] -lgfortran -lm" instead of "gfortran [...]".
I hope we now got that clear :) When I have time, I suspect that this
post will find its way to the gfortran documentation.
PS: these code examples don't use ISO_C_BINDING but the old-school
mixed-language programming style, which is not as portable and requires
knowledge of your Fortran compiler calling conventions.
--
FX
>
> PS: these code examples don't use ISO_C_BINDING but the old-school
> mixed-language programming style, which is not as portable and requires
> knowledge of your Fortran compiler calling conventions.
>
Thanks, FX, for your generous post.
Of the many variations that present themselves for mixed code with this
example, I chose to have main in fortran, and simply call the c++ function
we've written for dot product.
The fortran is:
program vector3
implicit none
real(kind=8), external :: dot_product_from_cplusplus
integer index, i
integer, parameter :: some_kind_number = selected_real_kind (p=16)
real (kind = some_kind_number), dimension(4):: vec_a, vec_b
real (kind = some_kind_number) :: res
index = 4
do i = 1, index
vec_a(i)= i**.5
vec_b(i)= (-1.0)*(i**2)
end do
res = dot_product_from_cplusplus(vec_a, vec_b)
write (*,*) vec_a, vec_b
write (*,*) res
end program vector3
! gfortran2 -o vector3 b.o vector3.f95 >text55.txt 2>text56.txt
! vector3 >text55.txt 2>text56.txt
!! end of the fortran part begin c++ function
#include <cmath>
#include <vector>
#include <iostream>
#include <iterator>
double dot_product_from_cplusplus (const std::vector<double>& vec_a, const
std::vector<double>& vec_b)
{
if ( vec_a.size() != vec_b.size() )
{
std::cerr << "Vectors for dot product are not same size!\n";
return 0.0;
}
double sum = 0;
for ( std::size_t i = 0; i < vec_a.size(); ++i )
{
sum += vec_a[i] * vec_b[i];
}
return std::pow(sum, .5);
}
// g++ -c b.cpp
// end function begin list of linker errors
b.o:b.cpp:(.text+0xe): undefined reference to `std::string::size() const'
b.o:b.cpp:(.text+0x52): undefined reference to
`std::string::operator[](unsigned int) const'
b.o:b.cpp:(.text+0x8b): undefined reference to
`std::string::operator[](unsigned int) const'
b.o:b.cpp:(.text+0xcc): undefined reference to
`std::string::operator[](unsigned int) const'
b.o:b.cpp:(.text+0x116): undefined reference to
`std::ios_base::Init::Init()'
b.o:b.cpp:(.text+0x135): undefined reference to
`std::ios_base::Init::~Init()'
b.o:b.cpp:(.text+0x1a3): undefined reference to `std::cerr'
b.o:b.cpp:(.text+0x1a8): undefined reference to `std::basic_ostream<char,
std::char_traits<char> >& std::operator<< <std::char_traits<char>
>(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
C:\DOCUME~1\dan\LOCALS~1\Temp/ccIftQ0c.o:vector3.f95:(.text+0xb2): undefined
reference to `_dot_product_from_cplusplus_'
collect2: ld returned 1 exit status
Yikes. The ultimate build command that brought such consternation from
gfortran, which in my installation is gfortran2.exe, was
gfortran2 -o vector3 b.o vector3.f95
Grateful for any tips.
Please read posts twice before asking again. I quote myself:
>> (b) use the second kind of linking command, ie with "g++ [...]
>> [-lgfortranbegin] -lgfortran -lm" instead of "gfortran [...]"
So, that's:
g++ -c b.cpp
gfortran -c vector3.f95
g++ -o vector b.o vector3.o -lgfortranbegin -lgfortran -lm
However, that won't work and will give:
/usr/libexec/gcc/i686-apple-darwin8/4.0.1/ld: Undefined symbols:
_dot_product_from_cplusplus_
I don't know C++ (never written a single line of it) but it seems that
the name of your dot_product_from_cplusplus is mangled into something
awful (__Z26dot_product_from_cplusplusRKSt6vectorIdSaIdEES3_), to encode
its type and the type of its arguments. So, you need to find a C++ expert
to ask him how to do that.
Final point, I'm not sure your prototype:
> double dot_product_from_cplusplus (const std::vector<double>& vec_a, const
> std::vector<double>& vec_b)
can interact with Fortran: from what I understand, "std::vector<double>&
vec_a" is actually more like a C pointer to a "struct" than a pointer to
a "double". Again, I can't help you much, but I suspect this way of doing
it won't work.
--
FX
The C++ code needs to be wrapped in an "extern C" scope to turn off name
mangling.
Jan
As I told utab, you are highly unlikely to be able to interface between
a Fortran array and a C++ std::vector.
The correct signature for this function if you want to be able to call
it from Fortran is:
extern "C" double dot_product_from_cplusplus(double const * a,
double const * b)
The 'extern "C"' is necessary to disable C++ name mangling, which is
used to make symbols that distinguish by arguments for overloading
purposes (Fortran accomplishes the same thing by using a generic
interface to tie external symbols with different names together).
I set a goal for an easier inter-syntax problem and was able to get results:
Main is in fortran:
PROGRAM Vector_Sqrt
IMPLICIT NONE
!add function from c++
real(kind=8), external :: sqrt_from_c
INTEGER, PARAMETER :: dp = KIND(0.0d0)
REAL(DP) :: four_vector(4), j
INTEGER :: i
DO i = 1, 4
j= 1.0*i
four_vector(i) = SQRT_FROM_C(j)
! four_vector(i) = SQRT(REAL(i, DP))
ENDDO
WRITE(*,'(4F19.16)') four_vector
END
! g++ -c cat.cpp && gfortran2 -c vector4.f95
! gfortran2 cat.o vector4.o
,and the sqrt is from c++:
//$ cat v.c
#include <math.h>
extern "C" double sqrt_from_c_ (double *x)
{
return sqrt(*x);
}
// g++ -c cat.cpp
Much of this notation is mixed and sloppy. I'd been playing around with
different things and got this to work. I still don't know what cat would
mean to FX. I did find out that the double ampersand *does* work on dos
and comes highly recommended when using multiple commands.
I'll clean up this notation and try to get squared away with a dotproduct,
which doesn't require much more than a sqrt. It's not surprising that
passing a pointer to a real would be effective here. It would seem that
adding extern "C" and a trailing underscore is what works.
Thanks for your help.
"cat" is the Unix command that outputs the content of a file.
--
FX
> Once again, you can use "gcc" instead of "gfortran" in the linking stage,
> but
> that requires to add "-lgfortranbegin -lgfortran -lm":
>
> $ gcc -c v.c && gfortran -c u.f90 && gcc u.o
> v.o -lgfortranbegin -lgfortran -lm && ./a.out
> 1.41421356237310 1.41421356237310
>
>
> You can do the same things with C++ code, just (a) use g++ instead of c++
> and (b) use the second kind of linking command, ie with "g++ [...]
> [-lgfortranbegin] -lgfortran -lm" instead of "gfortran [...]".
>
> I hope we now got that clear :) When I have time, I suspect that this
> post will find its way to the gfortran documentation.
>
>
> PS: these code examples don't use ISO_C_BINDING but the old-school
> mixed-language programming style, which is not as portable and requires
> knowledge of your Fortran compiler calling conventions.
When we're talking about calling from a different syntax, I think the
ultimate link command must come from the syntax that has main. If main is
in fortran, I think that this is what this error message means, with
g++ dam1.o damian1.o -lgfortran -lm
damian1.o:damian1.f03:(.text+0x11): undefined reference to
`__gfortran_set_options'
C:/gcc/i386-pc-mingw32/lib/libmingw32.a(main.o): In function `main':
/home/gfortran/gcc-home/workshop/mingw32/objdir/../mingw-runtime-3.13/main.c:73:
undefined reference to `_WinMain@16'
collect2: ld returned 1 exit status
! gfortran2 -c damian1.f03
! gfortran2 dam1.o damian1.o
! g++ dam1.o damian1.o -lgfortran -lm
! -lgfortranbegin
^^^^ Other things I've tried.
For C and Fortran, yes. For C++, it's harder because C++ requires runtime
libraries to be linked in, so it's easier to always link with g++ when
you link in C++ code, whatever the main program is.
> g++ dam1.o damian1.o -lgfortran -lm
> damian1.o:damian1.f03:(.text+0x11): undefined reference to
> `__gfortran_set_options'
> C:/gcc/i386-pc-mingw32/lib/libmingw32.a(main.o): In function `main':
> /home/gfortran/gcc-home/workshop/mingw32/objdir/../mingw-runtime-3.13/main.c:73:
> undefined reference to `_WinMain@16'
> collect2: ld returned 1 exit status
I've said it explicit in the post you answer to: when you link code that
has a Fortran main and you don't use gfortran as linker command, you need
to use "-lgfortranbegin -lgfortran -lm".
> ! g++ dam1.o damian1.o -lgfortran -lm
> ! -lgfortranbegin
> ^^^^ Other things I've tried.
That's interesting. What was the error message?
--
FX
Well, if these three are the only ones on the menu, and for the purpose of
passing two vectors, and only today it occured to me to just pass vec_a and
vec_b as opposed to their addresses, I would claim that main in c++ were
similarly constrained.
>
>> g++ dam1.o damian1.o -lgfortran -lm
>> damian1.o:damian1.f03:(.text+0x11): undefined reference to
>> `__gfortran_set_options'
>> C:/gcc/i386-pc-mingw32/lib/libmingw32.a(main.o): In function `main':
>> /home/gfortran/gcc-home/workshop/mingw32/objdir/../mingw-runtime-3.13/main.c:73:
>> undefined reference to `_WinMain@16'
>> collect2: ld returned 1 exit status
>
> I've said it explicit in the post you answer to: when you link code that
> has a Fortran main and you don't use gfortran as linker command, you need
> to use "-lgfortranbegin -lgfortran -lm".
>
>> ! g++ dam1.o damian1.o -lgfortran -lm
>> ! -lgfortranbegin
>> ^^^^ Other things I've tried.
>
> That's interesting. What was the error message?
I didn't save it, and my gfortran capability is gone. OP awaits annc. of
new release.