From: glen herrmannsfeldt on
robin <robin_v(a)bigpond.com> wrote:
(snip, I wrote)

> | I wonder if it is possible to call qsort() from Fortran.

> Why bother?
> Quicksort is a relatively short procedure to code,
> and codes in Fortran are readily available.

Well, first I didn't say that there was a reason, but...

As far as I know Fortran still doesn't allow the pointer tricks
needed to implement something like C's qsort().

(Given a pointer to an array of an arbitrary type, generate
pointers to all the array elements without actually knowing
or needing to know in advance what that type is.)

Note that, despite the name and the fact that I noted it
in the previous post, there is no requirement that qsort()
implement the quicksort algorithm.

-- glen

From: Ron Shepard on
In article <hm1vir$2vp$1(a)naig.caltech.edu>,
glen herrmannsfeldt <gah(a)ugcs.caltech.edu> wrote:

> As far as I know Fortran still doesn't allow the pointer tricks
> needed to implement something like C's qsort().

You can write indexed sort routines (using any algorithm you want)
in which the sort routine never needs to look at the individual
array elements, it works only with the integer array indices. The
comparisons are a little more expensive this way (they need a
subroutine call each), but it results in a very flexible interface.

$.02 -Ron Shepard
From: glen herrmannsfeldt on
Ron Shepard <ron-shepard(a)nospam.comcast.net> wrote:
> In article <hm1vir$2vp$1(a)naig.caltech.edu>,
> glen herrmannsfeldt <gah(a)ugcs.caltech.edu> wrote:

>> As far as I know Fortran still doesn't allow the pointer tricks
>> needed to implement something like C's qsort().

> You can write indexed sort routines (using any algorithm you want)
> in which the sort routine never needs to look at the individual
> array elements, it works only with the integer array indices. The
> comparisons are a little more expensive this way (they need a
> subroutine call each), but it results in a very flexible interface.

qsort() does a call for each comparison, but it can do the swap itself.

I might see how to write one in Fortran that does a subroutine call
for comparison and one for each swap, if you can pass a pointer
to an arbitrary type (like C's void pointer).

One way to use qsort() is to pass an array of pointers to the
actual elements being sorted. It also works well with structures,
as long as the elements aren't too big. (Such that data movement
time dominates.)

Since Fortran now has C_FUNLOC(), though, it shouldn't be hard
to use qsort(). So far, I haven't managed to compile a
call with C_FUNLOC(), though.

-- glen

From: Ron Shepard on
In article <hm24il$423$1(a)naig.caltech.edu>,
glen herrmannsfeldt <gah(a)ugcs.caltech.edu> wrote:

> One way to use qsort() is to pass an array of pointers to the
> actual elements being sorted. It also works well with structures,
> as long as the elements aren't too big. (Such that data movement
> time dominates.)

This is what I meant by an indexed sort. You pass an integer array.
The actual data does not move, so data movement never dominates no
matter how large the elements are. It is only the integers that are
swapped, shifted, inserted, etc. This is all straightforward to do
in fortran, even f77, although f90 simplifies some of the details by
allowing user defined data types to be sorted and by keeping the
data type definitions localized in the same module as the comparison
routines.

$.02 -Ron Shepard
From: James Van Buskirk on
"robin" <robin_v(a)bigpond.com> wrote in message
news:yaZgn.9422$pv.3490(a)news-server.bigpond.net.au...

> "glen herrmannsfeldt" <gah(a)ugcs.caltech.edu> wrote in message
> news:hlv6t2$7d7$3(a)naig.caltech.edu...

> | I wonder if it is possible to call qsort() from Fortran.

> Why bother?
> Quicksort is a relatively short procedure to code,
> and codes in Fortran are readily available.

For example,

C:\gfortran\clf\qsort>type qstest.f90
module ifaces
use ISO_C_BINDING
implicit none
interface
function getch() bind(C,name='getch')
use ISO_C_BINDING
implicit none
integer(C_INT) getch
end function getch
subroutine qsort(base, nmemb, size, compar) bind(C,name='qsort')
use ISO_C_BINDING
implicit none
type(C_PTR), value :: base
integer(C_SIZE_T), value :: nmemb
integer(C_SIZE_T), value :: size
type(C_FUNPTR), value :: compar
end subroutine qsort
end interface
end module ifaces

module funcs
use ISO_C_BINDING
implicit none
type, bind(C) :: mytype
integer(C_INT) key
real(C_FLOAT) data
end type mytype
interface operator(<=)
module procedure LessOrEqual
end interface operator(<=)
contains
function compar(v1, v2) bind(C)
integer(C_INT) compar
type(C_PTR), value :: v1, v2
type(mytype), pointer :: p1, p2

call C_F_POINTER(v1,p1)
call C_F_POINTER(v2,p2)
if(.NOT.(p1 <= p2)) then
compar = 1
else if(.NOT.(p2 <= p1)) then
compar = -1
else
compar = 0
end if
end function compar
function LessOrEqual(v1, v2)
logical LessOrEqual
type(mytype), intent(in) :: v1, v2

LessOrEqual = v1%key <= v2%key
end function LessOrEqual
end module funcs

program qstest
use ifaces
use funcs
use ISO_C_BINDING
implicit none
integer(C_SIZE_T) MAX
type(mytype), allocatable, target :: arr(:)
integer i
integer(C_INT) result
real harvest

MAX = 20
allocate(arr(MAX))
do i = 1, MAX
call random_number(harvest)
arr(i) = mytype(10*MAX*harvest, i)
end do
write(*,'(a)') 'Unsorted data:'
do i = 1, MAX
write(*,*) i,arr(i)
end do
write(*,'(a)',advance='no') 'Press any key to sort the values.'
result = getch()
call qsort(C_LOC(arr(1)), MAX, C_SIZEOF(arr(1)), C_FUNLOC(compar))
write(*,'()')
do i = 1, MAX
write(*,*) i,arr(i)
end do
end program qstest

C:\gfortran\clf\qsort>gfortran qstest.f90 -oqstest

C:\gfortran\clf\qsort>qstest
Unsorted data:
1 199 1.0000000
2 113 2.0000000
3 193 3.0000000
4 149 4.0000000
5 73 5.0000000
6 96 6.0000000
7 14 7.0000000
8 1 8.0000000
9 69 9.0000000
10 68 10.000000
11 43 11.000000
12 26 12.000000
13 180 13.000000
14 77 14.000000
15 89 15.000000
16 132 16.000000
17 3 17.000000
18 130 18.000000
19 129 19.000000
20 64 20.000000
Press any key to sort the values.
1 1 8.0000000
2 3 17.000000
3 14 7.0000000
4 26 12.000000
5 43 11.000000
6 64 20.000000
7 68 10.000000
8 69 9.0000000
9 73 5.0000000
10 77 14.000000
11 89 15.000000
12 96 6.0000000
13 113 2.0000000
14 129 19.000000
15 130 18.000000
16 132 16.000000
17 149 4.0000000
18 180 13.000000
19 193 3.0000000
20 199 1.0000000

Looking at the date of creation of the directory above, I probably
posted a generic qsort algorithm in Fortran on 04/24/2008.
Example adapted from
http://groups.engin.umd.umich.edu/CIS/course.des/cis400/c/sort.html

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end