11
11
integer (kind= int64), parameter :: radix_mask_i64 = 255_int64
12
12
13
13
contains
14
+ ! For int8, radix sort becomes counting sort, so buffer is not needed
14
15
pure subroutine radix_sort_u8_helper (N , arr )
15
- integer (kind= int64 ), intent (in ) :: N
16
+ integer (kind= int_size ), intent (in ) :: N
16
17
integer (kind= int8), dimension (N), intent (inout ) :: arr
17
- integer (kind= int64 ) :: i
18
+ integer (kind= int_size ) :: i
18
19
integer :: bin_idx
19
- integer (kind= int64 ), dimension (- 128 :127 ) :: counts
20
+ integer (kind= int_size ), dimension (- 128 :127 ) :: counts
20
21
counts(:) = 0
21
22
do i = 1 , N
22
23
bin_idx = arr(i)
@@ -33,12 +34,12 @@ pure subroutine radix_sort_u8_helper(N, arr)
33
34
end subroutine
34
35
35
36
pure subroutine radix_sort_u16_helper (N , arr , buf )
36
- integer (kind= int64 ), intent (in ) :: N
37
+ integer (kind= int_size ), intent (in ) :: N
37
38
integer (kind= int16), dimension (N), intent (inout ) :: arr
38
39
integer (kind= int16), dimension (N), intent (inout ) :: buf
39
- integer (kind= int64 ) :: i
40
+ integer (kind= int_size ) :: i
40
41
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
42
43
c0(:) = 0
43
44
c1(:) = 0
44
45
do i = 1 , N
@@ -64,12 +65,12 @@ pure subroutine radix_sort_u16_helper(N, arr, buf)
64
65
end subroutine
65
66
66
67
pure subroutine radix_sort_u32_helper (N , arr , buf )
67
- integer (kind= int64 ), intent (in ) :: N
68
+ integer (kind= int_size ), intent (in ) :: N
68
69
integer (kind= int32), dimension (N), intent (inout ) :: arr
69
70
integer (kind= int32), dimension (N), intent (inout ) :: buf
70
- integer (kind= int64 ) :: i
71
+ integer (kind= int_size ) :: i
71
72
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
73
74
c0(:) = 0
74
75
c1(:) = 0
75
76
c2(:) = 0
@@ -113,12 +114,12 @@ pure subroutine radix_sort_u32_helper(N, arr, buf)
113
114
end subroutine radix_sort_u32_helper
114
115
115
116
pure subroutine radix_sort_u64_helper (N , arr , buffer )
116
- integer (kind= int64 ), intent (in ) :: N
117
+ integer (kind= int_size ), intent (in ) :: N
117
118
integer (kind= int64), dimension (N), intent (inout ) :: arr
118
119
integer (kind= int64), dimension (N), intent (inout ) :: buffer
119
- integer (kind= int64 ) :: i
120
+ integer (kind= int_size ) :: i
120
121
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
122
123
c0(:) = 0
123
124
c1(:) = 0
124
125
c2(:) = 0
@@ -200,15 +201,15 @@ end subroutine radix_sort_u64_helper
200
201
pure module subroutine int8_radix_sort(array, reverse)
201
202
integer (kind= int8), dimension (:), intent (inout ) :: array
202
203
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 )
206
207
call radix_sort_u8_helper(N, array)
207
208
if (optval(reverse, .false. )) then
208
209
do i = 1 , N/ 2
209
- buffer_item = array(i)
210
+ item = array(i)
210
211
array(i) = array(N - i + 1 )
211
- array(N - i + 1 ) = buffer_item
212
+ array(N - i + 1 ) = item
212
213
end do
213
214
end if
214
215
end subroutine int8_radix_sort
@@ -217,13 +218,13 @@ pure module subroutine int16_radix_sort(array, work, reverse)
217
218
integer (kind= int16), dimension (:), intent (inout ) :: array
218
219
integer (kind= int16), dimension (:), intent (inout ), target , optional :: work
219
220
logical , intent (in ), optional :: reverse
220
- integer (kind= int64 ) :: i, N, start, middle, end
221
+ integer (kind= int_size ) :: i, N, start, middle, end
221
222
integer (kind= int16), dimension (:), pointer :: buffer
222
223
integer (kind= int16) :: item
223
224
logical :: use_internal_buffer
224
- N = size (array, kind= int64 )
225
+ N = size (array, kind= int_size )
225
226
if (present (work)) then
226
- if (size (work, kind= int64 ) < N) then
227
+ if (size (work, kind= int_size ) < N) then
227
228
error stop " int16_radix_sort: work array is too small."
228
229
end if
229
230
use_internal_buffer = .false.
@@ -233,6 +234,9 @@ pure module subroutine int16_radix_sort(array, work, reverse)
233
234
allocate (buffer(N))
234
235
end if
235
236
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.
236
240
if (array(1 ) >= 0 .and. array(N) < 0 ) then
237
241
start = 1
238
242
end = N
@@ -266,13 +270,13 @@ pure module subroutine int32_radix_sort(array, work, reverse)
266
270
integer (kind= int32), dimension (:), intent (inout ) :: array
267
271
integer (kind= int32), dimension (:), intent (inout ), target , optional :: work
268
272
logical , intent (in ), optional :: reverse
269
- integer (kind= int64 ) :: i, N, start, middle, end
273
+ integer (kind= int_size ) :: i, N, start, middle, end
270
274
integer (kind= int32), dimension (:), pointer :: buffer
271
275
integer (kind= int32) :: item
272
276
logical :: use_internal_buffer
273
- N = size (array, kind= int64 )
277
+ N = size (array, kind= int_size )
274
278
if (present (work)) then
275
- if (size (work, kind= int64 ) < N) then
279
+ if (size (work, kind= int_size ) < N) then
276
280
error stop " int32_radix_sort: work array is too small."
277
281
end if
278
282
use_internal_buffer = .false.
@@ -316,14 +320,14 @@ module subroutine sp_radix_sort(array, work, reverse)
316
320
real (kind= sp), dimension (:), intent (inout ), target :: array
317
321
real (kind= sp), dimension (:), intent (inout ), target , optional :: work
318
322
logical , intent (in ), optional :: reverse
319
- integer (kind= int64 ) :: i, N, pos, rev_pos
323
+ integer (kind= int_size ) :: i, N, pos, rev_pos
320
324
integer (kind= int32), dimension (:), pointer :: arri32
321
325
integer (kind= int32), dimension (:), pointer :: buffer
322
326
real (kind= sp) :: item
323
327
logical :: use_internal_buffer
324
- N = size (array, kind= int64 )
328
+ N = size (array, kind= int_size )
325
329
if (present (work)) then
326
- if (size (work, kind= int64 ) < N) then
330
+ if (size (work, kind= int_size ) < N) then
327
331
error stop " sp_radix_sort: work array is too small."
328
332
end if
329
333
use_internal_buffer = .false.
@@ -334,6 +338,14 @@ module subroutine sp_radix_sort(array, work, reverse)
334
338
end if
335
339
call c_f_pointer(c_loc(array), arri32, [N])
336
340
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.
337
349
if (arri32(1 ) >= 0 .and. arri32(N) < 0 ) then
338
350
pos = 1
339
351
rev_pos = N
@@ -361,13 +373,13 @@ pure module subroutine int64_radix_sort(array, work, reverse)
361
373
integer (kind= int64), dimension (:), intent (inout ) :: array
362
374
integer (kind= int64), dimension (:), intent (inout ), target , optional :: work
363
375
logical , intent (in ), optional :: reverse
364
- integer (kind= int64 ) :: i, N, start, middle, end
376
+ integer (kind= int_size ) :: i, N, start, middle, end
365
377
integer (kind= int64), dimension (:), pointer :: buffer
366
378
integer (kind= int64) :: item
367
379
logical :: use_internal_buffer
368
- N = size (array, kind= int64 )
380
+ N = size (array, kind= int_size )
369
381
if (present (work)) then
370
- if (size (work, kind= int64 ) < N) then
382
+ if (size (work, kind= int_size ) < N) then
371
383
error stop " int64_radix_sort: work array is too small."
372
384
end if
373
385
use_internal_buffer = .false.
@@ -411,14 +423,14 @@ module subroutine dp_radix_sort(array, work, reverse)
411
423
real (kind= dp), dimension (:), intent (inout ), target :: array
412
424
real (kind= dp), dimension (:), intent (inout ), target , optional :: work
413
425
logical , intent (in ), optional :: reverse
414
- integer (kind= int64 ) :: i, N, pos, rev_pos
426
+ integer (kind= int_size ) :: i, N, pos, rev_pos
415
427
integer (kind= int64), dimension (:), pointer :: arri64
416
428
integer (kind= int64), dimension (:), pointer :: buffer
417
429
real (kind= dp) :: item
418
430
logical :: use_internal_buffer
419
- N = size (array, kind= int64 )
431
+ N = size (array, kind= int_size )
420
432
if (present (work)) then
421
- if (size (work, kind= int64 ) < N) then
433
+ if (size (work, kind= int_size ) < N) then
422
434
error stop " sp_radix_sort: work array is too small."
423
435
end if
424
436
use_internal_buffer = .false.
0 commit comments