Recently I'm trying to call qsort to sort a long integer array on Linux, however, the result looks like wrong. And I try to call qsort to sort the same array on Windows, finding that the result is correct. Is there something wrong when I call qsort on Linux? Any suggestions will be appreciated!
The codes call qsort on Linux are as follows:
Module Share_Type_GPU Type Element_Type_GPU Integer :: Row Integer :: Col Integer(8) :: Index Double Precision :: Val End Type End Module Share_Type_GPU Subroutine Qsort_COO_Linux_GPU Use Global_Variables, ONLY: Nelem,Nevab,Mposn Use,Intrinsic :: Iso_C_Binding, ONLY: C_Size_T Use Ifport, ONLY: Qsort_Element_Types_GPU => Qsort Use Share_Type_GPU Interface Subroutine Qsort(Array, Len, Isize, Comp) Use, Intrinsic :: Iso_C_Binding, Only: C_Size_T Use Share_Type_GPU Type(Element_Type_GPU) Array(Len) Integer(C_Size_T) Len, Isize Integer(8), External :: Comp End Subroutine Qsort End Interface Type(Element_Type_GPU) :: C(Nelem*Nevab*Nevab) Integer(8), External :: Cmp_Function_GPU Integer (C_Size_T) :: Size_Of_Element, Size_Of_Array Integer I Do I=1,Nelem*Nevab*Nevab C(I)%Val = COO_Value(I) C(I)%Row = COO_Index(I,1) C(I)%Col = COO_Index(I,2) C(I)%Index = COO_Index(I,2)*Mposn+COO_Index(I,1) ! Long integer larger than integer(4), so use integer(8) End Do Size_Of_Array = Size(C) Size_Of_Element = Sizeof(C(1)) Call Qsort(C, Size_Of_Array, Size_Of_Element, Cmp_Function_GPU) Do I=1,Nelem*Nevab*Nevab COO_Value(I) = C(I)%Val COO_Index(I,1)= C(I)%Row COO_Index(I,2)= C(I)%Col End Do Return End Subroutine Function Cmp_Function_GPU(C1, C2) Use Share_Type_GPU Implicit None Type(Element_Type_GPU), Intent(In) :: C1 Type(Element_Type_GPU), Intent(In) :: C2 Integer(8) :: Cmp_Function_GPU Cmp_Function_GPU=C1%Index-C2%Index End Function
Thank you very much!
We don't have a full compilable example here, but I suggest going back to the documentation for the ifport implementation of qsort and comparing what you have done with the example there. One obvious thing that stands out to me is that you have declared the compare function to have a return value of integer(8), when the documentation suggests integer(2).
Might be onto something with the integer(2) vs. integer(8)
If the comp argument is passed by reference, the endianness of windows provide a little leeway to get it wrong.
If I pass an integer(8) value to a routine expecting integer(2) on windows, it will work as expected because the first two bytes
of an integer(8) value that would fit into an integer(2) are the same as the integer(2)
For example integer(8) value of 1 on windows shows up in memory as 01 00 00 00 00 00 00 00
and integer(2) value of 1 shows up in memory as 01 00. So if I pass the address of integer(8) 1 to a routine expecting integer(2), it
On unix systems the order in memory is swapped to something a bit for user friendly, such that integer(8) value of 1 is
00 00 00 00 00 00 00 01
and integer(2) value of 1 is
But then passing integer(8) by reference to a routine expecting integer(2), the subroutine will see the first 2 bytes of the integer(8) number, and so it would see 0 instead of 1.