1111 integer (kind= int64), parameter :: radix_mask_i64 = 255_int64
1212
1313contains
14+ ! For int8, radix sort becomes counting sort, so buffer is not needed
1415 pure subroutine radix_sort_u8_helper (N , arr )
15- integer (kind= int64 ), intent (in ) :: N
16+ integer (kind= int_size ), intent (in ) :: N
1617 integer (kind= int8), dimension (N), intent (inout ) :: arr
17- integer (kind= int64 ) :: i
18+ integer (kind= int_size ) :: i
1819 integer :: bin_idx
19- integer (kind= int64 ), dimension (- 128 :127 ) :: counts
20+ integer (kind= int_size ), dimension (- 128 :127 ) :: counts
2021 counts(:) = 0
2122 do i = 1 , N
2223 bin_idx = arr(i)
@@ -33,12 +34,12 @@ pure subroutine radix_sort_u8_helper(N, arr)
3334 end subroutine
3435
3536 pure subroutine radix_sort_u16_helper (N , arr , buf )
36- integer (kind= int64 ), intent (in ) :: N
37+ integer (kind= int_size ), intent (in ) :: N
3738 integer (kind= int16), dimension (N), intent (inout ) :: arr
3839 integer (kind= int16), dimension (N), intent (inout ) :: buf
39- integer (kind= int64 ) :: i
40+ integer (kind= int_size ) :: i
4041 integer :: b, b0, b1
41- integer (kind= int64 ), dimension (0 :radix_mask) :: c0, c1
42+ integer (kind= int_size ), dimension (0 :radix_mask) :: c0, c1
4243 c0(:) = 0
4344 c1(:) = 0
4445 do i = 1 , N
@@ -64,12 +65,12 @@ pure subroutine radix_sort_u16_helper(N, arr, buf)
6465 end subroutine
6566
6667 pure subroutine radix_sort_u32_helper (N , arr , buf )
67- integer (kind= int64 ), intent (in ) :: N
68+ integer (kind= int_size ), intent (in ) :: N
6869 integer (kind= int32), dimension (N), intent (inout ) :: arr
6970 integer (kind= int32), dimension (N), intent (inout ) :: buf
70- integer (kind= int64 ) :: i
71+ integer (kind= int_size ) :: i
7172 integer :: b, b0, b1, b2, b3
72- integer (kind= int64 ), dimension (0 :radix_mask) :: c0, c1, c2, c3
73+ integer (kind= int_size ), dimension (0 :radix_mask) :: c0, c1, c2, c3
7374 c0(:) = 0
7475 c1(:) = 0
7576 c2(:) = 0
@@ -113,12 +114,12 @@ pure subroutine radix_sort_u32_helper(N, arr, buf)
113114 end subroutine radix_sort_u32_helper
114115
115116 pure subroutine radix_sort_u64_helper (N , arr , buffer )
116- integer (kind= int64 ), intent (in ) :: N
117+ integer (kind= int_size ), intent (in ) :: N
117118 integer (kind= int64), dimension (N), intent (inout ) :: arr
118119 integer (kind= int64), dimension (N), intent (inout ) :: buffer
119- integer (kind= int64 ) :: i
120+ integer (kind= int_size ) :: i
120121 integer (kind= int64) :: b, b0, b1, b2, b3, b4, b5, b6, b7
121- integer (kind= int64 ), dimension (0 :radix_mask) :: c0, c1, c2, c3, c4, c5, c6, c7
122+ integer (kind= int_size ), dimension (0 :radix_mask) :: c0, c1, c2, c3, c4, c5, c6, c7
122123 c0(:) = 0
123124 c1(:) = 0
124125 c2(:) = 0
@@ -200,15 +201,15 @@ end subroutine radix_sort_u64_helper
200201 pure module subroutine int8_radix_sort(array, reverse)
201202 integer (kind= int8), dimension (:), intent (inout ) :: array
202203 logical , intent (in ), optional :: reverse
203- integer (kind= int8) :: buffer_item
204- integer (kind= int64 ) :: i, N
205- N = size (array, kind= int64 )
204+ integer (kind= int8) :: item
205+ integer (kind= int_size ) :: i, N
206+ N = size (array, kind= int_size )
206207 call radix_sort_u8_helper(N, array)
207208 if (optval(reverse, .false. )) then
208209 do i = 1 , N/ 2
209- buffer_item = array(i)
210+ item = array(i)
210211 array(i) = array(N - i + 1 )
211- array(N - i + 1 ) = buffer_item
212+ array(N - i + 1 ) = item
212213 end do
213214 end if
214215 end subroutine int8_radix_sort
@@ -217,13 +218,13 @@ pure module subroutine int16_radix_sort(array, work, reverse)
217218 integer (kind= int16), dimension (:), intent (inout ) :: array
218219 integer (kind= int16), dimension (:), intent (inout ), target , optional :: work
219220 logical , intent (in ), optional :: reverse
220- integer (kind= int64 ) :: i, N, start, middle, end
221+ integer (kind= int_size ) :: i, N, start, middle, end
221222 integer (kind= int16), dimension (:), pointer :: buffer
222223 integer (kind= int16) :: item
223224 logical :: use_internal_buffer
224- N = size (array, kind= int64 )
225+ N = size (array, kind= int_size )
225226 if (present (work)) then
226- if (size (work, kind= int64 ) < N) then
227+ if (size (work, kind= int_size ) < N) then
227228 error stop " int16_radix_sort: work array is too small."
228229 end if
229230 use_internal_buffer = .false.
@@ -233,6 +234,9 @@ pure module subroutine int16_radix_sort(array, work, reverse)
233234 allocate (buffer(N))
234235 end if
235236 call radix_sort_u16_helper(N, array, buffer)
237+ ! After calling `radix_sort_u<width>_helper. The array is sorted as unsigned integers.
238+ ! In the view of signed arrsy, the negative numbers are sorted but in the tail of the array.
239+ ! Use binary search to find the boundary, and move then to correct position.
236240 if (array(1 ) >= 0 .and. array(N) < 0 ) then
237241 start = 1
238242 end = N
@@ -266,13 +270,13 @@ pure module subroutine int32_radix_sort(array, work, reverse)
266270 integer (kind= int32), dimension (:), intent (inout ) :: array
267271 integer (kind= int32), dimension (:), intent (inout ), target , optional :: work
268272 logical , intent (in ), optional :: reverse
269- integer (kind= int64 ) :: i, N, start, middle, end
273+ integer (kind= int_size ) :: i, N, start, middle, end
270274 integer (kind= int32), dimension (:), pointer :: buffer
271275 integer (kind= int32) :: item
272276 logical :: use_internal_buffer
273- N = size (array, kind= int64 )
277+ N = size (array, kind= int_size )
274278 if (present (work)) then
275- if (size (work, kind= int64 ) < N) then
279+ if (size (work, kind= int_size ) < N) then
276280 error stop " int32_radix_sort: work array is too small."
277281 end if
278282 use_internal_buffer = .false.
@@ -316,14 +320,14 @@ module subroutine sp_radix_sort(array, work, reverse)
316320 real (kind= sp), dimension (:), intent (inout ), target :: array
317321 real (kind= sp), dimension (:), intent (inout ), target , optional :: work
318322 logical , intent (in ), optional :: reverse
319- integer (kind= int64 ) :: i, N, pos, rev_pos
323+ integer (kind= int_size ) :: i, N, pos, rev_pos
320324 integer (kind= int32), dimension (:), pointer :: arri32
321325 integer (kind= int32), dimension (:), pointer :: buffer
322326 real (kind= sp) :: item
323327 logical :: use_internal_buffer
324- N = size (array, kind= int64 )
328+ N = size (array, kind= int_size )
325329 if (present (work)) then
326- if (size (work, kind= int64 ) < N) then
330+ if (size (work, kind= int_size ) < N) then
327331 error stop " sp_radix_sort: work array is too small."
328332 end if
329333 use_internal_buffer = .false.
@@ -334,6 +338,14 @@ module subroutine sp_radix_sort(array, work, reverse)
334338 end if
335339 call c_f_pointer(c_loc(array), arri32, [N])
336340 call radix_sort_u32_helper(N, arri32, buffer)
341+ ! After calling `radix_sort_u<width>_helper. The array is sorted as unsigned integers.
342+ ! The positive real number is sorted, guaranteed by IEEE-754 standard.
343+ ! But the negative real number is sorted in a reversed order, and also in the tail of array.
344+ ! Remark that -0.0 is the minimum nagative integer, so using radix sort, -0.0 is naturally lesser than 0.0.
345+ ! In IEEE-754 standard, the bit representation of `Inf` is greater than all positive real numbers,
346+ ! and the `-Inf` is lesser than all negative real numbers. So the order of `Inf, -Inf` is ok.
347+ ! The bit representation of `NaN` may be positive or negative integers in different machine,
348+ ! thus if the array contains `NaN`, the result is undefined.
337349 if (arri32(1 ) >= 0 .and. arri32(N) < 0 ) then
338350 pos = 1
339351 rev_pos = N
@@ -361,13 +373,13 @@ pure module subroutine int64_radix_sort(array, work, reverse)
361373 integer (kind= int64), dimension (:), intent (inout ) :: array
362374 integer (kind= int64), dimension (:), intent (inout ), target , optional :: work
363375 logical , intent (in ), optional :: reverse
364- integer (kind= int64 ) :: i, N, start, middle, end
376+ integer (kind= int_size ) :: i, N, start, middle, end
365377 integer (kind= int64), dimension (:), pointer :: buffer
366378 integer (kind= int64) :: item
367379 logical :: use_internal_buffer
368- N = size (array, kind= int64 )
380+ N = size (array, kind= int_size )
369381 if (present (work)) then
370- if (size (work, kind= int64 ) < N) then
382+ if (size (work, kind= int_size ) < N) then
371383 error stop " int64_radix_sort: work array is too small."
372384 end if
373385 use_internal_buffer = .false.
@@ -411,14 +423,14 @@ module subroutine dp_radix_sort(array, work, reverse)
411423 real (kind= dp), dimension (:), intent (inout ), target :: array
412424 real (kind= dp), dimension (:), intent (inout ), target , optional :: work
413425 logical , intent (in ), optional :: reverse
414- integer (kind= int64 ) :: i, N, pos, rev_pos
426+ integer (kind= int_size ) :: i, N, pos, rev_pos
415427 integer (kind= int64), dimension (:), pointer :: arri64
416428 integer (kind= int64), dimension (:), pointer :: buffer
417429 real (kind= dp) :: item
418430 logical :: use_internal_buffer
419- N = size (array, kind= int64 )
431+ N = size (array, kind= int_size )
420432 if (present (work)) then
421- if (size (work, kind= int64 ) < N) then
433+ if (size (work, kind= int_size ) < N) then
422434 error stop " sp_radix_sort: work array is too small."
423435 end if
424436 use_internal_buffer = .false.
0 commit comments