// Written by Kaze, 2022-Mar-31
// The idea is to compare the built-in qsort vs my 'Magnetica' Quicksort, using "perf stat -d" in this fashion: https://github.com/facebook/zstd/issues/2551
// How to compile?
/*
F:\Quicksort_says_rev9+_finished>type make_elf.sh
gcc -S -O3 -m64 -static -fomit-frame-pointer QS_bench_r13.c -o QS_bench_r13.elf.asm -D_N_HIGH_PRIORITY_GCC
gcc -O3 -m64 -static -fomit-frame-pointer QS_bench_r13.c -o QS_bench_r13_GCC11.2.1.elf -D_N_HIGH_PRIORITY_GCC
gcc -O3 -m64 -static -fomit-frame-pointer QS_bench_r13.c -o QS_bench_r13_GCC11.2.1_FULL-FLEDGED.elf -D_N_HIGH_PRIORITY_GCC -DFinishWithInsertionSort
x86_64-w64-mingw32-gcc -O3 -m64 -static -fomit-frame-pointer QS_bench_r13.c -o QS_bench_r13_GCC11.2.1.exe -D_N_HIGH_PRIORITY
x86_64-w64-mingw32-gcc -O3 -m64 -static -fomit-frame-pointer QS_bench_r13.c -o QS_bench_r13_GCC11.2.1_FULL-FLEDGED.exe -D_N_HIGH_PRIORITY -DFinishWithInsertionSort

F:\Quicksort_says_rev9+_finished>type MAKE_EXE.bat
@rem icl QS_bench_r8.c /arch:SSE4.1 /FAcs /O3 /Qopenmp /Qopenmp-link:static -DCommence_OpenMP -D_N_HIGH_PRIORITY
icl QS_bench_r13.c /S /O3 -D_N_HIGH_PRIORITY
icl QS_bench_r13.c /FAcs /O3 /FeQS_bench_r13_ICL15.0_64bit_FULL-FLEDGED.exe -DFinishWithInsertionSort -D_N_HIGH_PRIORITY
icl QS_bench_r13.c /FAcs /O3 /FeQS_bench_r13_ICL15.0_64bit.exe -D_N_HIGH_PRIORITY

F:\Quicksort_says_rev9+_finished>
*/

// My thread with the Magnetica's source and binaries (Linux and Windows):
// https://www.overclock.net/threads/benchmark-quicksort-says-sorting-2-billion-qwords.1794855/
// https://www.qb64.org/forum/index.php?topic=3518.msg137645#msg137645
/*
' Written by Sanmayce, 2021-Nov-06
' The indexes are signed, but the elements are unsigned.
_Define A-Z As _INTEGER64
Sub Quicksort_QB64_v3 (QWORDS~&&())
    InsertionsortTHRESHOLD = 0 '19
    Left = LBound(QWORDS~&&)
    Right = UBound(QWORDS~&&)
    ReDim Stack&&(Left To Right)
    StackPtr = 0
    StackPtr = StackPtr + 1
    Stack&&(StackPtr + LeftMargin) = Left
    StackPtr = StackPtr + 1
    Stack&&(StackPtr + LeftMargin) = Right
    Do 'Until StackPtr = 0
        Right = Stack&&(StackPtr)
        Left = Stack&&(StackPtr - 1)
        StackPtr = StackPtr - 2
        Do 'Until Left >= Right

            ''Classica' partitioning [
            'Pivot~&& = QWORDS~&&((Left + Right) \ 2)
            'Indx = Left
            'Jndx = Right
            'Do
            '    Do While (QWORDS~&&(Indx) < Pivot~&&)
            '        Indx = Indx + 1
            '    Loop
            '    Do While (QWORDS~&&(Jndx) > Pivot~&&)
            '        Jndx = Jndx - 1
            '    Loop
            '    If Indx <= Jndx Then
            '        If Indx < Jndx Then Swap QWORDS~&&(Indx), QWORDS~&&(Jndx)
            '        Indx = Indx + 1
            '        Jndx = Jndx - 1
            '    End If
            'Loop While Indx <= Jndx
            ''Classica' partitioning ]

            ' 'Magnetica' partitioning [
            Jndx = Right
            PL = Left
            PR = Left
            Swap QWORDS~&&((Left + Right) \ 2), QWORDS~&&(PR)
            Pivot~&& = QWORDS~&&(PR)
            Do While PR < Jndx
                If Pivot~&& > QWORDS~&&(PR + 1) Then
                    Swap QWORDS~&&(PL), QWORDS~&&(PR + 1)
                    PL = PL + 1
                    PR = PR + 1
                ElseIf Pivot~&& = QWORDS~&&(PR + 1) Then
                    PR = PR + 1
                Else ' < i.e. Pivot~&& < QWORDS~&&(PR + 1)
                    Do While Pivot~&& < QWORDS~&&(Jndx)
                        Jndx = Jndx - 1
                    Loop
                    If PR + 1 < Jndx Then Swap QWORDS~&&(PR + 1), QWORDS~&&(Jndx)
                    Jndx = Jndx - 1
                End If
            Loop
            Jndx = PL - 1
            Indx = PR + 1
            ' 'Magnetica' partitioning ]

            If Indx + InsertionsortTHRESHOLD < Right Then 'if the remaining chunk is bigger than 'InsertionsortTHRESHOLD' push it to stack, otherwise leave all such chunks unsorted
                StackPtr = StackPtr + 2
                Stack&&(StackPtr - 1) = Indx
                Stack&&(StackPtr) = Right
            End If
            Right = Jndx
        Loop Until Left >= Right
    Loop Until StackPtr = 0
    'Left = LBound(QWORDS~&&)
    'Right = UBound(QWORDS~&&)
    'For i = Left + 1 To Right ' i.e. 1 to size-1 omitting the first (which is 0)
    '    j = i
    '    Do While j >= 1 'Nah, start using a sentinel
    '        If QWORDS~&&(j - 1) > QWORDS~&&(j) Then Swap QWORDS~&&(j - 1), QWORDS~&&(j) Else Exit Do
    '        j = j - 1
    '    Loop
    'Next i
End Sub
*/

// On i5-7200U 3.1GHz (2cores/4threads), 64bit code by gcc version 10.2.1, Fedora 33:
/*
[kaze@kaze ~]$ cd /run/media/kaze/Sanmayce_223GB_A/Quicksort_says_rev3
[kaze@kaze Quicksort_says_rev3]$ dir
22338618_QWORDS.bin  Fedora-Workstation-Live-x86_64-35-1.2.iso	Px437_Cordata_PPC-400.ttf  Quicksort_says      Quicksort_says_rev3_Kaby-Lake_Fedora-33.png
bench.sh	     MEM.H					QS_bench_r3.c		   Quicksort_says.bas  Quicksort_says_rev3_Kaby-Lake_Windows-10.png
ColumnChart.ico      mobythesaurus.txt				QS_bench_r3.exe		   Quicksort_says.exe  Sir_Tony_Hoare_IMG_5125.png
[kaze@kaze Quicksort_says_rev3]$ gcc -O3 QS_bench_r3.c -o QS_bench_r3
QS_bench_r3.c:473:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
  473 | g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}
      | ^
QS_bench_r3.c: In function ‘g’:
QS_bench_r3.c:473:1: warning: type of ‘d’ defaults to ‘int’ [-Wimplicit-int]
QS_bench_r3.c:473:1: warning: type of ‘h’ defaults to ‘int’ [-Wimplicit-int]
QS_bench_r3.c: In function ‘main’:
QS_bench_r3.c:557:6: warning: implicit declaration of function ‘strcmp’ [-Wimplicit-function-declaration]
  557 |  if (strcmp(argv[2],"many")==0) {
      |      ^~~~~~
[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 qsort few
Allocating AUX-Buffer 21MB ...
Allocating Master-Buffer 17043MB ...
Sorting in single-thread 2233861800 elements...
Checking whether sort went correct... OK. Unique keys = 10

 Performance counter stats for './QS_bench_r3 qsort few':

        325,465.05 msec task-clock:u              #    0.998 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         4,363,063      page-faults:u             #    0.013 M/sec                  
   980,631,883,041      cycles:u                  #    3.013 GHz                      (50.00%)
 3,279,551,895,331      instructions:u            #    3.34  insn per cycle           (62.50%)
   650,482,999,545      branches:u                # 1998.626 M/sec                    (62.50%)
     5,582,924,930      branch-misses:u           #    0.86% of all branches          (62.50%)
   734,186,209,415      L1-dcache-loads:u         # 2255.807 M/sec                    (62.50%)
     6,753,617,333      L1-dcache-load-misses:u   #    0.92% of all L1-dcache accesses  (62.50%)
       404,414,575      LLC-loads:u               #    1.243 M/sec                    (50.00%)
       111,254,842      LLC-load-misses:u         #   27.51% of all LL-cache accesses  (50.00%)

     326.101784425 seconds time elapsed

     317.871539000 seconds user
       5.577791000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 Magnetica  few
Allocating AUX-Buffer 21MB ...
Allocating Master-Buffer 17043MB ...
Sorting in single-thread 2233861800 elements...
Checking whether sort went correct... OK. Unique keys = 10

 Performance counter stats for './QS_bench_r3 Magnetica few':

         45,479.14 msec task-clock:u              #    1.000 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         4,363,068      page-faults:u             #    0.096 M/sec                  
   121,955,292,590      cycles:u                  #    2.682 GHz                      (50.00%)
   112,449,514,935      instructions:u            #    0.92  insn per cycle           (62.50%)
    24,092,559,780      branches:u                #  529.750 M/sec                    (62.50%)
     3,384,288,209      branch-misses:u           #   14.05% of all branches          (62.50%)
    13,329,400,797      L1-dcache-loads:u         #  293.088 M/sec                    (62.50%)
     1,655,811,975      L1-dcache-load-misses:u   #   12.42% of all L1-dcache accesses  (62.50%)
        70,845,055      LLC-loads:u               #    1.558 M/sec                    (50.00%)
        62,316,430      LLC-load-misses:u         #   87.96% of all LL-cache accesses  (50.00%)

      45.492587322 seconds time elapsed

      39.738044000 seconds user
       5.413636000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 BM  few
Allocating AUX-Buffer 21MB ...
Allocating Master-Buffer 17043MB ...
Sorting in single-thread 2233861800 elements...
Checking whether sort went correct... OK. Unique keys = 10

 Performance counter stats for './QS_bench_r3 BM few':

         51,751.74 msec task-clock:u              #    1.000 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         4,363,064      page-faults:u             #    0.084 M/sec                  
   140,850,991,285      cycles:u                  #    2.722 GHz                      (50.00%)
   141,773,758,594      instructions:u            #    1.01  insn per cycle           (62.50%)
    29,021,682,740      branches:u                #  560.787 M/sec                    (62.50%)
     2,964,754,548      branch-misses:u           #   10.22% of all branches          (62.49%)
    20,759,616,908      L1-dcache-loads:u         #  401.139 M/sec                    (62.50%)
     2,253,507,095      L1-dcache-load-misses:u   #   10.86% of all L1-dcache accesses  (62.50%)
       240,693,428      LLC-loads:u               #    4.651 M/sec                    (50.00%)
       119,509,033      LLC-load-misses:u         #   49.65% of all LL-cache accesses  (50.00%)

      51.765804273 seconds time elapsed

      45.999839000 seconds user
       5.392254000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 qsort many
Allocating FILE-Buffer 23MB ...
Allocating AUX-Buffer 189MB ...
Allocating Master-Buffer 18938MB ...
Sorting in single-thread 2482300900 elements...
Checking whether sort went correct... OK. Unique keys = 2847531

 Performance counter stats for './QS_bench_r3 qsort many':

        517,942.56 msec task-clock:u              #    0.999 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         4,896,779      page-faults:u             #    0.009 M/sec                  
 1,569,421,552,908      cycles:u                  #    3.030 GHz                      (50.00%)
 2,937,315,064,269      instructions:u            #    1.87  insn per cycle           (62.50%)
   656,656,940,988      branches:u                # 1267.818 M/sec                    (62.50%)
    25,008,235,993      branch-misses:u           #    3.81% of all branches          (62.50%)
   675,474,160,813      L1-dcache-loads:u         # 1304.149 M/sec                    (62.50%)
     8,374,868,618      L1-dcache-load-misses:u   #    1.24% of all L1-dcache accesses  (62.50%)
       244,454,547      LLC-loads:u               #    0.472 M/sec                    (50.00%)
       132,791,156      LLC-load-misses:u         #   54.32% of all LL-cache accesses  (50.00%)

     518.237032044 seconds time elapsed

     508.735040000 seconds user
       5.950954000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 Magnetica many
Allocating FILE-Buffer 23MB ...
Allocating AUX-Buffer 189MB ...
Allocating Master-Buffer 18938MB ...
Sorting in single-thread 2482300900 elements...
Checking whether sort went correct... OK. Unique keys = 2847531

 Performance counter stats for './QS_bench_r3 Magnetica many':

        230,292.26 msec task-clock:u              #    1.000 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         4,896,782      page-faults:u             #    0.021 M/sec                  
   686,398,758,890      cycles:u                  #    2.981 GHz                      (50.00%)
   801,299,477,504      instructions:u            #    1.17  insn per cycle           (62.50%)
   152,341,819,141      branches:u                #  661.515 M/sec                    (62.50%)
    19,420,019,786      branch-misses:u           #   12.75% of all branches          (62.50%)
   105,227,165,554      L1-dcache-loads:u         #  456.929 M/sec                    (62.50%)
     9,758,775,155      L1-dcache-load-misses:u   #    9.27% of all L1-dcache accesses  (62.50%)
       331,205,631      LLC-loads:u               #    1.438 M/sec                    (50.00%)
       260,265,720      LLC-load-misses:u         #   78.58% of all LL-cache accesses  (50.00%)

     230.399202449 seconds time elapsed

     222.654274000 seconds user
       5.973146000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 BM many
Allocating FILE-Buffer 23MB ...
Allocating AUX-Buffer 189MB ...
Allocating Master-Buffer 18938MB ...
Sorting in single-thread 2482300900 elements...
Checking whether sort went correct... OK. Unique keys = 2847531

 Performance counter stats for './QS_bench_r3 BM many':

        234,206.73 msec task-clock:u              #    1.000 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         4,896,781      page-faults:u             #    0.021 M/sec                  
   698,588,697,890      cycles:u                  #    2.983 GHz                      (50.00%)
   656,081,987,764      instructions:u            #    0.94  insn per cycle           (62.50%)
   165,692,577,479      branches:u                #  707.463 M/sec                    (62.50%)
    18,927,109,180      branch-misses:u           #   11.42% of all branches          (62.50%)
    85,146,879,545      L1-dcache-loads:u         #  363.554 M/sec                    (62.50%)
     8,623,541,343      L1-dcache-load-misses:u   #   10.13% of all L1-dcache accesses  (62.50%)
       286,352,303      LLC-loads:u               #    1.223 M/sec                    (50.00%)
       227,490,519      LLC-load-misses:u         #   79.44% of all LL-cache accesses  (50.00%)

     234.306277225 seconds time elapsed

     226.632611000 seconds user
       5.938060000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 qsort ALL
Allocating FILE-Buffer 1916MB ...
Allocating AUX-Buffer 15329MB ...
Allocating Master-Buffer 15329MB ...
Sorting in single-thread 2009333753 elements...
Checking whether sort went correct... OK. Unique keys = 1912608132

 Performance counter stats for './QS_bench_r3 qsort ALL':

        520,097.93 msec task-clock:u              #    0.993 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         7,849,014      page-faults:u             #    0.015 M/sec                  
 1,553,894,682,781      cycles:u                  #    2.988 GHz                      (50.00%)
 2,271,179,443,512      instructions:u            #    1.46  insn per cycle           (62.50%)
   536,952,307,468      branches:u                # 1032.406 M/sec                    (62.50%)
    28,368,595,067      branch-misses:u           #    5.28% of all branches          (62.50%)                           
   520,144,933,578      L1-dcache-loads:u         # 1000.090 M/sec                    (62.50%)
     6,723,006,421      L1-dcache-load-misses:u   #    1.29% of all L1-dcache accesses  (62.50%)
       193,261,861      LLC-loads:u               #    0.372 M/sec                    (50.00%)
       102,759,148      LLC-load-misses:u         #   53.17% of all LL-cache accesses  (50.00%)

     524.002327535 seconds time elapsed

     504.423911000 seconds user
      12.294510000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 Magnetica ALL
Allocating FILE-Buffer 1916MB ...
Allocating AUX-Buffer 15329MB ...
Allocating Master-Buffer 15329MB ...
Sorting in single-thread 2009333753 elements...
Checking whether sort went correct... OK. Unique keys = 1912608132

 Performance counter stats for './QS_bench_r3 Magnetica ALL':

        306,913.60 msec task-clock:u              #    0.990 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         7,849,020      page-faults:u             #    0.026 M/sec                  
   899,578,515,950      cycles:u                  #    2.931 GHz                      (50.00%)
 1,077,947,210,852      instructions:u            #    1.20  insn per cycle           (62.50%)
   202,031,197,397      branches:u                #  658.267 M/sec                    (62.50%)
    25,788,554,132      branch-misses:u           #   12.76% of all branches          (62.50%)
   143,089,373,092      L1-dcache-loads:u         #  466.220 M/sec                    (62.50%)
     7,361,011,433      L1-dcache-load-misses:u   #    5.14% of all L1-dcache accesses  (62.50%)
       240,367,987      LLC-loads:u               #    0.783 M/sec                    (50.00%)
       189,560,929      LLC-load-misses:u         #   78.86% of all LL-cache accesses  (50.00%)

     310.137967617 seconds time elapsed

     292.453199000 seconds user
      12.266850000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ perf stat -d ./QS_bench_r3 BM ALL
Allocating FILE-Buffer 1916MB ...
Allocating AUX-Buffer 15329MB ...
Allocating Master-Buffer 15329MB ...
Sorting in single-thread 2009333753 elements...
Checking whether sort went correct... OK. Unique keys = 1912608132

 Performance counter stats for './QS_bench_r3 BM ALL':

        322,688.09 msec task-clock:u              #    0.992 CPUs utilized          
                 0      context-switches:u        #    0.000 K/sec                  
                 0      cpu-migrations:u          #    0.000 K/sec                  
         7,849,403      page-faults:u             #    0.024 M/sec                  
   943,352,167,992      cycles:u                  #    2.923 GHz                      (50.00%)
   896,389,731,553      instructions:u            #    0.95  insn per cycle           (62.50%)
   226,893,780,871      branches:u                #  703.137 M/sec                    (62.50%)
    26,011,308,958      branch-misses:u           #   11.46% of all branches          (62.50%)
   119,844,660,142      L1-dcache-loads:u         #  371.395 M/sec                    (62.50%)
     7,940,603,646      L1-dcache-load-misses:u   #    6.63% of all L1-dcache accesses  (62.50%)
       258,555,901      LLC-loads:u               #    0.801 M/sec                    (50.00%)
       217,482,356      LLC-load-misses:u         #   84.11% of all LL-cache accesses  (50.00%)

     325.339098420 seconds time elapsed

     306.791354000 seconds user
      13.564926000 seconds sys


[kaze@kaze Quicksort_says_rev3]$ 
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> // Needed for uint32_t
#include<time.h>
#ifdef Commence_OpenMP
#include <omp.h>
#endif

void swap(uint64_t *a, uint64_t *b) {
  uint64_t t = *a;
  *a = *b;
  *b = t;
}

void QuickSortHoare(uint64_t array[], int64_t low, int64_t high) {
int64_t I,J;
uint64_t Pivot;

	if (low < high) {
	//swap(&array[(low + high)>>1], &array[high]);
	//Pivot=array[high];
	Pivot=array[(low + high)>>1];
	I = low; J = high;
	do {
                while (array[I] < Pivot) I = I + 1;
                while (array[J] > Pivot) J = J - 1;
	        if (I <= J) {
			swap(&array[I], &array[J]);
			I += 1;
			J -= 1;
		}
	} while (I <= J);
	//swap(&array[I], &array[high]);
// Problems with GCC and ICL, with bigdata:
/*
		#ifdef Commence_OpenMP
		#pragma omp parallel sections
		#endif
		{
			#ifdef Commence_OpenMP
			#pragma omp section
			#endif
			{
			QuickSortHoare(array, low, J);
			}
			#ifdef Commence_OpenMP
			#pragma omp section
			#endif
			{
			QuickSortHoare(array, I, high);
			}
  		}
*/
			QuickSortHoare(array, low, J);
			QuickSortHoare(array, I, high);
	}//if (low < high) {
}


void quicksort_Bentley_McIlroy_3way_partitioning(uint64_t a[], int64_t l, int64_t r)
{ 
	int64_t i = l-1, j = r, p = l-1, q = r; 
	int64_t k; 
	uint64_t v;
	if (r <= l) return;
	swap(&a[r], &a[(r+l)>>1]); // Modified by Kaze
	v = a[r];
	for (;;)
	{
		while (a[++i] < v) ;
		while (v < a[--j]) if (j == l) break;
		if (i >= j) break;
		swap(&a[i], &a[j]);
		if (a[i] == v) { p++; swap(&a[p], &a[i]); }
		if (v == a[j]) { q--; swap(&a[j], &a[q]); }
	}
	swap(&a[i], &a[r]); 
	j = i-1; i = i+1;
	for (k = l; k < p; k++, j--) swap(&a[k], &a[j]);
	for (k = r-1; k > q; k--, i++) swap(&a[i], &a[k]);
// Problems with GCC and ICL, with bigdata:
/*
		#ifdef Commence_OpenMP
		#pragma omp parallel sections
		#endif
		{
			#ifdef Commence_OpenMP
			#pragma omp section
			#endif
			{
	quicksort_Bentley_McIlroy_3way_partitioning(a, l, j);
			}
			#ifdef Commence_OpenMP
			#pragma omp section
			#endif
			{
	quicksort_Bentley_McIlroy_3way_partitioning(a, i, r);
			}
  		}
*/
	quicksort_Bentley_McIlroy_3way_partitioning(a, l, j);
	quicksort_Bentley_McIlroy_3way_partitioning(a, i, r);
}

/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; mark_description "-S -O3 -D_N_HIGH_PRIORITY";

;418 void quicksort_Bentley_McIlroy_3way_partitioning(uint64_t a[], int64_t l, int64_t r)
;419 { 
;420 	int64_t i = l-1, j = r, p = l-1, q = r; 
;421 	int64_t k; 
;422 	uint64_t v = a[r];
;423 	if (r <= l) return;
;424 	for (;;)
;425 	{
;426 		while (a[++i] < v) ;
;427 		while (v < a[--j]) if (j == l) break;
;428 		if (i >= j) break;
;429 		swap(&a[i], &a[j]);
;430 		if (a[i] == v) { p++; swap(&a[p], &a[i]); }
;431 		if (v == a[j]) { q--; swap(&a[j], &a[q]); }
;432 	}
;433 	swap(&a[i], &a[r]); j = i-1; i = i+1;
;434 	for (k = l; k < p; k++, j--) swap(&a[k], &a[j]);
;435 	for (k = r-1; k > q; k--, i++) swap(&a[i], &a[k]);
;436 	quicksort_Bentley_McIlroy_3way_partitioning(a, l, j);
;437 	quicksort_Bentley_McIlroy_3way_partitioning(a, i, r);
;438 }

quicksort_Bentley_McIlroy_3way_partitioning	PROC 
; parameter 1: rcx
; parameter 2: rdx
; parameter 3: r8
.B2.1::                         ; Preds .B2.0
        push      rbx                                           ;419.1
        push      rsi                                           ;419.1
        push      rdi                                           ;419.1
        push      r12                                           ;419.1
        push      r13                                           ;419.1
        push      r14                                           ;419.1
        push      r15                                           ;419.1
        push      rbp                                           ;419.1
        sub       rsp, 88                                       ;419.1
        lea       r10, QWORD PTR [rcx+r8*8]                     ;422.15
        mov       rax, r8                                       ;421.2
        lea       r9, QWORD PTR [-1+r8]                         ;421.2
        mov       QWORD PTR [64+rsp], r9                        ;421.2
        mov       rbx, rax                                      ;421.2
        mov       QWORD PTR [56+rsp], r10                       ;421.2
        mov       rsi, rcx                                      ;421.2
        mov       QWORD PTR [72+rsp], r8                        ;421.2
                                
.B2.2::                         ; Preds .B2.42 .B2.1
        mov       r10, QWORD PTR [72+rsp]                       ;420.39
        lea       r9, QWORD PTR [-1+rdx]                        ;420.16
        mov       rdi, rbx                                      ;420.23
        mov       rax, r9                                       ;420.32
        mov       rbx, r10                                      ;420.39
        cmp       r10, rdx                                      ;423.11
        mov       rbp, QWORD PTR [rsi+r10*8]                    ;422.15
        jg        .B2.5         ; Prob 72%                      ;423.11
                                
.B2.3::                         ; Preds .B2.2
        add       rsp, 88                                       ;423.14
        pop       rbp                                           ;423.14
        pop       r15                                           ;423.14
        pop       r14                                           ;423.14
        pop       r13                                           ;423.14
        pop       r12                                           ;423.14
        pop       rdi                                           ;423.14
        pop       rsi                                           ;423.14
        pop       rbx                                           ;423.14
        ret                                                     ;423.14
                                
.B2.5::                         ; Preds .B2.2 .B2.17 .B2.18
        inc       r9                                            ;426.14
        lea       r11, QWORD PTR [rsi+r9*8]                     ;426.10
        mov       r8, QWORD PTR [r11]                           ;426.10
        cmp       r8, rbp                                       ;426.19
        jae       .B2.9         ; Prob 10%                      ;426.19
                                
.B2.6::                         ; Preds .B2.5
        xor       r8d, r8d                                      ;426.3
                                
.B2.7::                         ; Preds .B2.7 .B2.6
        inc       r8                                            ;426.3
        cmp       rbp, QWORD PTR [r11+r8*8]                     ;426.19
        ja        .B2.7         ; Prob 82%                      ;426.19
                                
.B2.8::                         ; Preds .B2.7
        add       r9, r8                                        ;426.14
        mov       r8, QWORD PTR [rsi+r9*8]                      ;429.3
                                
.B2.9::                         ; Preds .B2.8 .B2.5
        dec       rdi                                           ;427.18
        mov       r14, rdi                                      ;427.18
        cmp       rbp, QWORD PTR [rsi+rdi*8]                    ;427.14
        jae       .B2.14        ; Prob 10%                      ;427.14
                                
.B2.10::                        ; Preds .B2.9
        xor       r12d, r12d                                    ;
        lea       r13, QWORD PTR [rsi+rdi*8]                    ;427.14
        xor       r11d, r11d                                    ;
                                
.B2.11::                        ; Preds .B2.12 .B2.10
        dec       r11                                           ;427.3
        add       r12, -8                                       ;427.3
        lea       r15, QWORD PTR [1+r14+r11]                    ;427.22
        cmp       rdx, r15                                      ;427.31
        lea       rcx, QWORD PTR [r14+r11]                      ;427.22
        je        .B2.14        ; Prob 20%                      ;427.31
                                
.B2.12::                        ; Preds .B2.11
        mov       rdi, rcx                                      ;427.18
        cmp       rbp, QWORD PTR [r12+r13]                      ;427.14
        jb        .B2.11        ; Prob 82%                      ;427.14
                                
.B2.14::                        ; Preds .B2.11 .B2.12 .B2.9
        cmp       r9, rdi                                       ;428.12
        jge       .B2.19        ; Prob 20%                      ;428.12
                                
.B2.15::                        ; Preds .B2.14
        mov       r11, QWORD PTR [rsi+rdi*8]                    ;429.3
        mov       QWORD PTR [rsi+r9*8], r11                     ;429.3
        mov       QWORD PTR [rsi+rdi*8], r8                     ;429.3
        mov       r11, QWORD PTR [rsi+r9*8]                     ;430.7
        cmp       r11, rbp                                      ;430.15
        jne       .B2.17        ; Prob 78%                      ;430.15
                                
.B2.16::                        ; Preds .B2.15
        inc       rax                                           ;430.20
        mov       r8, QWORD PTR [rsi+rax*8]                     ;430.25
        mov       QWORD PTR [rsi+rax*8], r11                    ;430.25
        mov       QWORD PTR [rsi+r9*8], r8                      ;430.25
        mov       r8, QWORD PTR [rsi+rdi*8]                     ;431.12
                                
.B2.17::                        ; Preds .B2.16 .B2.15
        cmp       rbp, r8                                       ;431.12
        jne       .B2.5         ; Prob 78%                      ;431.12
                                
.B2.18::                        ; Preds .B2.17
        dec       r10                                           ;431.20
        mov       r11, QWORD PTR [rsi+r10*8]                    ;431.25
        mov       QWORD PTR [rsi+rdi*8], r11                    ;431.25
        mov       QWORD PTR [rsi+r10*8], r8                     ;431.25
        jmp       .B2.5         ; Prob 100%                     ;431.25
                                
.B2.19::                        ; Preds .B2.14                  ; Infreq
        mov       rdi, QWORD PTR [72+rsp]                       ;433.2
        mov       r11, rdx                                      ;434.31
        mov       rbp, QWORD PTR [rsi+rdi*8]                    ;433.2
        mov       QWORD PTR [rsi+r9*8], rbp                     ;433.2
        lea       rbp, QWORD PTR [1+r9]                         ;433.37
        mov       QWORD PTR [rsi+rdi*8], r8                     ;433.2
        lea       r8, QWORD PTR [-1+r9]                         ;433.28
        sub       r11, r8                                       ;434.31
        mov       rdi, r8                                       ;433.22
        add       r11, -2                                       ;434.7
        mov       QWORD PTR [48+rsp], rbp                       ;433.31
        cmp       r11, 64                                       ;434.2
        jle       .B2.27        ; Prob 50%                      ;434.2
                                
.B2.20::                        ; Preds .B2.19                  ; Infreq
        cmp       rdx, rax                                      ;434.18
        jge       .B2.34        ; Prob 15%                      ;434.18
                                
.B2.21::                        ; Preds .B2.20                  ; Infreq
        sub       rax, rdx                                      ;434.2
        mov       r15d, 1                                       ;434.2
        mov       r12, rax                                      ;434.2
        shr       r12, 63                                       ;434.2
        add       r12, rax                                      ;434.2
        sar       r12, 1                                        ;434.2
        lea       r11, QWORD PTR [1+rax]                        ;434.2
        sub       r8, r11                                       ;434.31
        xor       r11d, r11d                                    ;434.2
        xor       r13d, r13d                                    ;
        inc       r8                                            ;434.31
        xor       r14d, r14d                                    ;
        test      r12, r12                                      ;434.2
        jbe       .B2.25        ; Prob 15%                      ;434.2
                                
.B2.22::                        ; Preds .B2.21                  ; Infreq
        mov       QWORD PTR [32+rsp], rsi                       ;434.31
        lea       r15, QWORD PTR [rsi+rdx*8]                    ;434.31
        mov       QWORD PTR [40+rsp], rdx                       ;434.31
        lea       rcx, QWORD PTR [rsi+rdi*8]                    ;434.31
                                
.B2.23::                        ; Preds .B2.23 .B2.22           ; Infreq
        mov       rdx, QWORD PTR [r14+rcx]                      ;434.31
        inc       r11                                           ;434.2
        mov       rsi, QWORD PTR [r13+r15]                      ;434.31
        mov       QWORD PTR [r13+r15], rdx                      ;434.31
        mov       QWORD PTR [r14+rcx], rsi                      ;434.31
        mov       rdx, QWORD PTR [-8+r14+rcx]                   ;434.31
        mov       rsi, QWORD PTR [8+r13+r15]                    ;434.31
        mov       QWORD PTR [8+r13+r15], rdx                    ;434.31
        add       r13, 16                                       ;434.2
        mov       QWORD PTR [-8+r14+rcx], rsi                   ;434.31
        add       r14, -16                                      ;434.2
        cmp       r11, r12                                      ;434.2
        jb        .B2.23        ; Prob 64%                      ;434.2
                                
.B2.24::                        ; Preds .B2.23                  ; Infreq
        mov       rsi, QWORD PTR [32+rsp]                       ;
        lea       r15, QWORD PTR [1+r11*2]                      ;434.2
        mov       rdx, QWORD PTR [40+rsp]                       ;
                                
.B2.25::                        ; Preds .B2.24 .B2.21           ; Infreq
        lea       r11, QWORD PTR [-1+r15]                       ;434.2
        cmp       rax, r11                                      ;434.2
        ja        .B2.33        ; Prob 84%                      ;434.2
        jmp       .B2.34        ; Prob 100%                     ;434.2
                                
.B2.27::                        ; Preds .B2.19                  ; Infreq
        cmp       rdx, rax                                      ;434.18
        jge       .B2.34        ; Prob 15%                      ;434.18
                                
.B2.28::                        ; Preds .B2.27                  ; Infreq
        sub       rax, rdx                                      ;434.2
        mov       r15d, 1                                       ;434.2
        mov       r12, rax                                      ;434.2
        shr       r12, 63                                       ;434.2
        add       r12, rax                                      ;434.2
        sar       r12, 1                                        ;434.2
        lea       r11, QWORD PTR [1+rax]                        ;434.2
        sub       r8, r11                                       ;434.31
        xor       r11d, r11d                                    ;434.2
        xor       r13d, r13d                                    ;
        inc       r8                                            ;434.31
        xor       r14d, r14d                                    ;
        test      r12, r12                                      ;434.2
        jbe       .B2.32        ; Prob 15%                      ;434.2
                                
.B2.29::                        ; Preds .B2.28                  ; Infreq
        mov       QWORD PTR [32+rsp], rsi                       ;434.31
        lea       r15, QWORD PTR [rsi+rdx*8]                    ;434.31
        mov       QWORD PTR [40+rsp], rdx                       ;434.31
        lea       rcx, QWORD PTR [rsi+rdi*8]                    ;434.31
                                
.B2.30::                        ; Preds .B2.30 .B2.29           ; Infreq
        mov       rdx, QWORD PTR [r14+rcx]                      ;434.31
        inc       r11                                           ;434.2
        mov       rsi, QWORD PTR [r13+r15]                      ;434.31
        mov       QWORD PTR [r13+r15], rdx                      ;434.31
        mov       QWORD PTR [r14+rcx], rsi                      ;434.31
        mov       rdx, QWORD PTR [-8+r14+rcx]                   ;434.31
        mov       rsi, QWORD PTR [8+r13+r15]                    ;434.31
        mov       QWORD PTR [8+r13+r15], rdx                    ;434.31
        add       r13, 16                                       ;434.2
        mov       QWORD PTR [-8+r14+rcx], rsi                   ;434.31
        add       r14, -16                                      ;434.2
        cmp       r11, r12                                      ;434.2
        jb        .B2.30        ; Prob 64%                      ;434.2
                                
.B2.31::                        ; Preds .B2.30                  ; Infreq
        mov       rsi, QWORD PTR [32+rsp]                       ;
        lea       r15, QWORD PTR [1+r11*2]                      ;434.2
        mov       rdx, QWORD PTR [40+rsp]                       ;
                                
.B2.32::                        ; Preds .B2.31 .B2.28           ; Infreq
        lea       r11, QWORD PTR [-1+r15]                       ;434.2
        cmp       rax, r11                                      ;434.2
        jbe       .B2.34        ; Prob 15%                      ;434.2
                                
.B2.33::                        ; Preds .B2.25 .B2.32           ; Infreq
        sub       rdi, r15                                      ;434.31
        lea       r11, QWORD PTR [rdx+r15]                      ;434.2
        mov       r12, QWORD PTR [-8+rsi+r11*8]                 ;434.31
        mov       r15, QWORD PTR [8+rsi+rdi*8]                  ;434.31
        mov       QWORD PTR [-8+rsi+r11*8], r15                 ;434.31
        mov       QWORD PTR [8+rsi+rdi*8], r12                  ;434.31
                                
.B2.34::                        ; Preds .B2.20 .B2.27 .B2.33 .B2.32 .B2.25
                                ;                               ; Infreq
        cmp       r10, QWORD PTR [64+rsp]                       ;435.20
        jge       .B2.41        ; Prob 0%                       ;435.20
                                
.B2.35::                        ; Preds .B2.34                  ; Infreq
        mov       rdi, QWORD PTR [72+rsp]                       ;435.28
        neg       r10                                           ;435.28
        xor       r13d, r13d                                    ;435.2
        mov       eax, 1                                        ;435.2
        lea       rbp, QWORD PTR [rdi+r9]                       ;435.28
        add       rbp, r10                                      ;435.28
        lea       r9, QWORD PTR [rdi+r10]                       ;435.2
        lea       r10, QWORD PTR [-1+rdi+r10]                   ;435.2
        mov       r11, r10                                      ;435.2
        shr       r11, 63                                       ;435.2
        lea       r9, QWORD PTR [-1+r9+r11]                     ;435.2
        xor       r11d, r11d                                    ;
        sar       r9, 1                                         ;435.2
        xor       r12d, r12d                                    ;
        test      r9, r9                                        ;435.2
        jbe       .B2.39        ; Prob 10%                      ;435.2
                                
.B2.36::                        ; Preds .B2.35                  ; Infreq
        mov       rdi, QWORD PTR [48+rsp]                       ;435.33
        lea       rax, QWORD PTR [rsi+rdi*8]                    ;435.33
        mov       rdi, QWORD PTR [56+rsp]                       ;435.33
                                
.B2.37::                        ; Preds .B2.37 .B2.36           ; Infreq
        mov       r14, QWORD PTR [-8+r12+rdi]                   ;435.33
        inc       r13                                           ;435.2
        mov       r15, QWORD PTR [r11+rax]                      ;435.33
        mov       QWORD PTR [r11+rax], r14                      ;435.33
        mov       QWORD PTR [-8+r12+rdi], r15                   ;435.33
        mov       r14, QWORD PTR [-16+r12+rdi]                  ;435.33
        mov       r15, QWORD PTR [8+r11+rax]                    ;435.33
        mov       QWORD PTR [8+r11+rax], r14                    ;435.33
        add       r11, 16                                       ;435.2
        mov       QWORD PTR [-16+r12+rdi], r15                  ;435.33
        add       r12, -16                                      ;435.2
        cmp       r13, r9                                       ;435.2
        jb        .B2.37        ; Prob 64%                      ;435.2
                                
.B2.38::                        ; Preds .B2.37                  ; Infreq
        lea       rax, QWORD PTR [1+r13*2]                      ;435.2
                                
.B2.39::                        ; Preds .B2.38 .B2.35           ; Infreq
        lea       rdi, QWORD PTR [-1+rax]                       ;435.2
        cmp       r10, rdi                                      ;435.2
        jbe       .B2.41        ; Prob 10%                      ;435.2
                                
.B2.40::                        ; Preds .B2.39                  ; Infreq
        mov       r9, QWORD PTR [48+rsp]                        ;435.2
        add       r9, rax                                       ;435.2
        shl       rax, 3                                        ;435.33
        neg       rax                                           ;435.33
        add       rax, QWORD PTR [56+rsp]                       ;435.33
        mov       r10, QWORD PTR [-8+rsi+r9*8]                  ;435.33
        mov       rdi, QWORD PTR [rax]                          ;435.33
        mov       QWORD PTR [-8+rsi+r9*8], rdi                  ;435.33
        mov       QWORD PTR [rax], r10                          ;435.33
                                
.B2.41::                        ; Preds .B2.34 .B2.39 .B2.40    ; Infreq
        mov       rcx, rsi                                      ;436.2
        call      quicksort_Bentley_McIlroy_3way_partitioning   ;436.2
                                
.B2.42::                        ; Preds .B2.41                  ; Infreq
        mov       rdx, rbp                                      ;437.2
        jmp       .B2.2         ; Prob 100%                     ;437.2
        ALIGN     16
                                
.B2.44::
; mark_end;
quicksort_Bentley_McIlroy_3way_partitioning ENDP
*/

// Magnetica r.5BB:
/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; mark_description "-S -O3 -D_N_HIGH_PRIORITY";

Quicksort_QB64_v9	PROC 
; parameter 1: rcx
; parameter 2: rdx
; parameter 3: r8
.B12.1::                        ; Preds .B12.0
        push      r13                                           ;1172.72
        push      r14                                           ;1172.72
        push      r15                                           ;1172.72
        push      rbp                                           ;1172.72
        mov       eax, 800024                                   ;1172.72
        call      __chkstk                                      ;1172.72
        sub       rsp, 800024                                   ;1172.72
        mov       eax, 2                                        ;1191.5
        mov       QWORD PTR [40+rsp], rdx                       ;1190.17
        mov       QWORD PTR [48+rsp], r8                        ;1191.17
                                
.B12.2::                        ; Preds .B12.20 .B12.1
        mov       rdx, QWORD PTR [32+rsp+rax*8]                 ;1193.17
        mov       r13, QWORD PTR [24+rsp+rax*8]                 ;1194.16
        add       rax, -2                                       ;1195.31
        cmp       r13, rdx                                      ;1197.47
        jge       .B12.20       ; Prob 10%                      ;1197.47
                                
.B12.3::                        ; Preds .B12.2
        mov       r9, r13                                       ;1199.13
                                
.B12.4::                        ; Preds .B12.18 .B12.3
        mov       r10, QWORD PTR [rcx+r13*8]                    ;1229.13
        lea       r15, QWORD PTR [r13+rdx]                      ;1229.48
        sar       r15, 1                                        ;1229.56
        mov       r14, r13                                      ;1200.13
        mov       r11, rdx                                      ;1198.13
        mov       rbp, r9                                       ;1199.13
        mov       r9, r14                                       ;1200.13
        mov       r8, QWORD PTR [rcx+r15*8]                     ;1229.13
        mov       QWORD PTR [rcx+r15*8], r10                    ;1229.13
        mov       QWORD PTR [rcx+r13*8], r8                     ;1229.13
                                
.B12.5::                        ; Preds .B12.4 .B12.13
        inc       r14                                           ;1282.27
        mov       r10, QWORD PTR [rcx+r14*8]                    ;1283.29
        cmp       r8, r10                                       ;1283.29
        ja        .B12.12       ; Prob 22%                      ;1283.29
                                
.B12.6::                        ; Preds .B12.5
        jae       .B12.13       ; Prob 50%                      ;1287.36
                                
.B12.7::                        ; Preds .B12.6
        mov       r15, QWORD PTR [rcx+r11*8]                    ;1288.35
        cmp       r8, r15                                       ;1288.35
        jae       .B12.11       ; Prob 10%                      ;1288.35
                                
.B12.9::                        ; Preds .B12.7 .B12.9
        dec       r11                                           ;1289.39
        mov       r15, QWORD PTR [rcx+r11*8]                    ;1288.35
        cmp       r8, r15                                       ;1288.35
        jb        .B12.9        ; Prob 82%                      ;1288.35
                                
.B12.11::                       ; Preds .B12.9 .B12.7
        mov       QWORD PTR [rcx+r14*8], r15                    ;1291.21
        dec       r14                                           ;1296.31
        mov       QWORD PTR [rcx+r11*8], r10                    ;1291.21
        dec       r11                                           ;1295.35
        jmp       .B12.13       ; Prob 100%                     ;1295.35
                                
.B12.12::                       ; Preds .B12.5
        mov       r15, QWORD PTR [rcx+rbp*8]                    ;1284.21
        mov       QWORD PTR [rcx+rbp*8], r10                    ;1284.21
        inc       rbp                                           ;1285.31
        mov       QWORD PTR [rcx+r14*8], r15                    ;1284.21
                                
.B12.13::                       ; Preds .B12.12 .B12.11 .B12.6
        cmp       r14, r11                                      ;1281.24
        jl        .B12.5        ; Prob 82%                      ;1281.24
                                
.B12.14::                       ; Preds .B12.13
        jle       .B12.16       ; Prob 78%                      ;1299.22
                                
.B12.15::                       ; Preds .B12.14
        mov       r8, QWORD PTR [8+rcx+r11*8]                   ;1300.21
        mov       r10, QWORD PTR [8+rcx+r14*8]                  ;1300.21
        mov       QWORD PTR [8+rcx+r14*8], r8                   ;1300.21
        mov       QWORD PTR [8+rcx+r11*8], r10                  ;1300.21
                                
.B12.16::                       ; Preds .B12.14 .B12.15
        inc       r14                                           ;1655.25
        cmp       rdx, r14                                      ;1730.49
        jle       .B12.18       ; Prob 62%                      ;1730.49
                                
.B12.17::                       ; Preds .B12.16
        add       rax, 2                                        ;1731.39
        mov       QWORD PTR [24+rsp+rax*8], r14                 ;1732.17
        mov       QWORD PTR [32+rsp+rax*8], rdx                 ;1733.17
                                
.B12.18::                       ; Preds .B12.17 .B12.16
        lea       rdx, QWORD PTR [-1+rbp]                       ;1654.25
        cmp       r13, rdx                                      ;1197.47
        jl        .B12.4        ; Prob 82%                      ;1197.47
                                
.B12.20::                       ; Preds .B12.18 .B12.2
        DB        15                                            ;1743.28
        DB        31                                            ;1743.28
        DB        64                                            ;1743.28
        DB        0                                             ;1743.28
        DB        15                                            ;1743.28
        DB        31                                            ;1743.28
        DB        128                                           ;1743.28
        DB        0                                             ;1743.28
        DB        0                                             ;1743.28
        DB        0                                             ;1743.28
        DB        0                                             ;1743.28
        test      rax, rax                                      ;1743.28
        jne       .B12.2        ; Prob 99%                      ;1743.28
                                
.B12.21::                       ; Preds .B12.20
        add       rsp, 800024                                   ;1753.1
        pop       rbp                                           ;1753.1
        pop       r15                                           ;1753.1
        pop       r14                                           ;1753.1
        pop       r13                                           ;1753.1
        ret                                                     ;1753.1
        ALIGN     16
                                
.B12.22::
; mark_end;
Quicksort_QB64_v9 ENDP
*/


//    _____                                __  .__               
//   /     \ _____     ____   ____   _____/  |_|__| ____ _____   
//  /  \ /  \\__  \   / ___\ /    \_/ __ \   __\  |/ ___\\__  \  
// /    Y    \/ __ \_/ /_/  >   |  \  ___/|  | |  \  \___ / __ \_
// \____|__  (____  /\___  /|___|  /\___  >__| |__|\___  >____  /
//         \/     \//_____/      \/     \/             \/     \/ 
void Quicksort_QB64_v4(uint64_t QWORDS[], int64_t Left, int64_t Right) {
    int InsertionsortTHRESHOLD = 0;
    int64_t Indx, Jndx, PL, PR;
    int64_t Stack[99999];
    int64_t StackPtr = 0;
    uint64_t Pivot;
    StackPtr++; Stack[StackPtr] = Left;
    StackPtr++; Stack[StackPtr] = Right;

    do {
        Right = Stack[StackPtr];
        Left = Stack[StackPtr - 1];
        StackPtr = StackPtr - 2;
        do {
            // 'Magnetica' partitioning rev.2[
            Jndx = Right;
            PL = Left;
            PR = Left;
            swap (&QWORDS[(Left + Right)>>1], &QWORDS[PR]);
            Pivot = QWORDS[PR];
            for (;PR < Jndx;) {
                PR = PR + 1;
                if (Pivot > QWORDS[PR]) {
                    swap (&QWORDS[PL], &QWORDS[PR]);
                    PL = PL + 1;
                //} else if (Pivot == QWORDS[PR]) {
                } else if (Pivot < QWORDS[PR]) {
                    for (;Pivot < QWORDS[Jndx];) {
                        Jndx = Jndx - 1;
                    }
                    if (PR < Jndx) swap (&QWORDS[PR], &QWORDS[Jndx]);
                    Jndx = Jndx - 1;
                    PR = PR - 1;
                }
            }
            Jndx = PL - 1;
            Indx = PR + 1;
            // 'Magnetica' partitioning rev.2]
/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; ae-64+2=76 bytes i.e. (94-76=18 less), 5/1 conditional/unconditional jumps i.e. 2-1=1 less unconditional jump
; 'Magnetica' partitioning, mainloop rev.2[
.B4.5::                         
  00064 48 ff c5         inc rbp                                
  00067 48 8b 14 e9      mov rdx, QWORD PTR [rcx+rbp*8]         
  0006b 4c 3b ea         cmp r13, rdx                           
  0006e 77 2c            ja .B4.14 
.B4.6::                         
  00070 73 39            jae .B4.15 
.B4.7::                         
  00072 4e 8b 3c d9      mov r15, QWORD PTR [rcx+r11*8]         
  00076 4d 3b ef         cmp r13, r15                           
  00079 73 0c            jae .B4.11 
.B4.9::                         
  0007b 49 ff cb         dec r11                                
  0007e 4e 8b 3c d9      mov r15, QWORD PTR [rcx+r11*8]         
  00082 4d 3b ef         cmp r13, r15                           
  00085 72 f4            jb .B4.9 
.B4.11::                        
  00087 49 3b eb         cmp rbp, r11                           
  0008a 7d 08            jge .B4.13 
.B4.12::                        
  0008c 4c 89 3c e9      mov QWORD PTR [rcx+rbp*8], r15         
  00090 4a 89 14 d9      mov QWORD PTR [rcx+r11*8], rdx         
.B4.13::                        
  00094 49 ff cb         dec r11                                
  00097 48 ff cd         dec rbp                                
  0009a eb 0f            jmp .B4.15 
.B4.14::                        
  0009c 4e 8b 3c f1      mov r15, QWORD PTR [rcx+r14*8]         
  000a0 4a 89 14 f1      mov QWORD PTR [rcx+r14*8], rdx         
  000a4 49 ff c6         inc r14                                
  000a7 4c 89 3c e9      mov QWORD PTR [rcx+rbp*8], r15         
.B4.15::                        
  000ab 49 3b eb         cmp rbp, r11                           
  000ae 7c b4            jl .B4.5 
; 'Magnetica' partitioning, mainloop rev.2]
*/

/*
            // 'Magnetica' partitioning [
            Jndx = Right;
            PL = Left;
            PR = Left;
            swap (&QWORDS[(Left + Right)>>1], &QWORDS[PR]);
            Pivot = QWORDS[PR];
            for (;PR < Jndx;) {
                if (Pivot > QWORDS[PR + 1]) {
                    swap (&QWORDS[PL], &QWORDS[PR + 1]);
                    PL = PL + 1;
                    PR = PR + 1;
                } else if (Pivot == QWORDS[PR + 1]) {
                    PR = PR + 1;
                } else {
                    for (;Pivot < QWORDS[Jndx];) {
                        Jndx = Jndx - 1;
                    }
                    if (PR + 1 < Jndx) swap (&QWORDS[PR + 1], &QWORDS[Jndx]);
                    Jndx = Jndx - 1;
                }
            }
            Jndx = PL - 1;
            Indx = PR + 1;
            // 'Magnetica' partitioning ]
*/
/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; c6-6a+2=94 bytes, 5/2 conditional/unconditional jumps
; 'Magnetica' partitioning, mainloop [
.B4.5::                         
  0006a 4e 3b 5c e9 08   cmp r11, QWORD PTR [8+rcx+r13*8]       
  0006f 77 37            ja .B4.15 
.B4.6::                         
  00071 75 08            jne .B4.8 
.B4.7::                         
  00073 49 89 d5         mov r13, rdx                           
  00076 48 ff c2         inc rdx                                
  00079 eb 48            jmp .B4.16 
.B4.8::                         
  0007b 4e 8b 34 c1      mov r14, QWORD PTR [rcx+r8*8]          
  0007f 4d 3b de         cmp r11, r14                           
  00082 73 0c            jae .B4.12 
.B4.10::                        
  00084 49 ff c8         dec r8                                 
  00087 4e 8b 34 c1      mov r14, QWORD PTR [rcx+r8*8]          
  0008b 4d 3b de         cmp r11, r14                           
  0008e 72 f4            jb .B4.10 
.B4.12::                        
  00090 4c 3b c2         cmp r8, rdx                            
  00093 7e 0e            jle .B4.14 
.B4.13::                        
  00095 4e 8b 7c e9 08   mov r15, QWORD PTR [8+rcx+r13*8]       
  0009a 4e 89 74 e9 08   mov QWORD PTR [8+rcx+r13*8], r14       
  0009f 4e 89 3c c1      mov QWORD PTR [rcx+r8*8], r15          
.B4.14::                        
  000a3 49 ff c8         dec r8                                 
  000a6 eb 1b            jmp .B4.16 
.B4.15::                        
  000a8 4e 8b 74 e9 08   mov r14, QWORD PTR [8+rcx+r13*8]       
  000ad 4e 8b 3c e1      mov r15, QWORD PTR [rcx+r12*8]         
  000b1 4e 89 34 e1      mov QWORD PTR [rcx+r12*8], r14         
  000b5 49 ff c4         inc r12                                
  000b8 4e 89 7c e9 08   mov QWORD PTR [8+rcx+r13*8], r15       
  000bd 49 89 d5         mov r13, rdx                           
  000c0 48 ff c2         inc rdx                                
.B4.16::                        
  000c3 4d 3b e8         cmp r13, r8                            
  000c6 7c a2            jl .B4.5 
; 'Magnetica' partitioning, mainloop ]
*/

            if (Indx + InsertionsortTHRESHOLD < Right) {
                StackPtr = StackPtr + 2;
                Stack[StackPtr - 1] = Indx;
                Stack[StackPtr] = Right;
            }
            Right = Jndx;
        } while (Left < Right);
    } while (StackPtr != 0);
}


// 113 lines of scalar C:
/*
00,001 #define StackEntries 99999
00,002 #define FinishWithInsertionSort
00,003 #define revision4
00,004 void swapUnconditional(uint64_t *a, uint64_t *b) { uint64_t t = *a; *a = *b; *b = t; }
00,005 #define minSO(x, y) (y ^ ((x ^ y) & -(x < y)))
00,006 #define maxSO(x, y) (x ^ ((x ^ y) & -(x < y)))
00,007 //    _____                                __  .__               
00,008 //   /     \ _____     ____   ____   _____/  |_|__| ____ _____   
00,009 //  /  \ /  \\__  \   / ___\ /    \_/ __ \   __\  |/ ___\\__  \  
00,010 // /    Y    \/ __ \_/ /_/  >   |  \  ___/|  | |  \  \___ / __ \_
00,011 // \____|__  (____  /\___  /|___|  /\___  >__| |__|\___  >____  /
00,012 //         \/     \//_____/      \/     \/             \/     \/ 
00,013 // Written by Sanmayce, 2021-Dec-02
00,014 void Quicksort_QB64_v7(uint64_t QWORDS[], int64_t Left, int64_t Right) {
00,015     #ifdef FinishWithInsertionSort
00,016     int InsertionsortTHRESHOLD = 17;
00,017     #else
00,018     int InsertionsortTHRESHOLD = 0;
00,019     #endif
00,020     int64_t Indx, Jndx, PL, PR;
00,021     int64_t Stack[StackEntries];
00,022     int64_t StackPtr = 0;
00,023     uint64_t Pivot;
00,024     int64_t LeftBackup = Left;
00,025     int64_t RightBackup = Right;
00,026     register uint64_t x0,x1,x2,x3,x4,x5,x6;
00,027     int o0,o1,o2,o3,o4,o5,o6;
00,028     int64_t TheMiddleOfMiddle;
00,029     int GearBox = 0; // 0 is Median of 3; 1 is Median of 7; Shifting to higher gear if BiggerPartition:SmallerPartition ratio is > 64:1
00,030     StackPtr++; Stack[StackPtr] = Left;
00,031     StackPtr++; Stack[StackPtr] = Right;
00,032     do {
00,033         Right = Stack[StackPtr];
00,034         Left = Stack[StackPtr - 1];
00,035         StackPtr = StackPtr - 2;
00,036         for(;(Left + InsertionsortTHRESHOLD < Right);) { // For instance, 1 + 17 < 19 i.e. (19-1)/4+6 < 19
00,037             Jndx = Right;
00,038             PL = Left;
00,039             PR = Left;
00,040     #ifdef FinishWithInsertionSort
00,041             TheMiddleOfMiddle = Left + ((Right-Left)>>2); // (4Left + Right - Left)/4; Caution: [TheMiddleOfMiddle+6] should be <= [Right] i.e. 6+(4Left + Right - Left)/4 <= Right or 4*6+(4Left + Right - Left) <= 4Right or 4*6 <= 3Right-3Left or (4*6)/3 <= Right-Left i.e. 8 <= Right-Left as a minimum condition to enter the 'for'.
00,042             x0 = QWORDS[TheMiddleOfMiddle+0];
00,043             x1 = QWORDS[TheMiddleOfMiddle+1];
00,044             x2 = QWORDS[TheMiddleOfMiddle+2];
00,045 if (GearBox == 0) { // Median of 5 proves more effective than 7, however 7 betters better the nastiest N^2
00,046             o0 = (x0>x1)+(x0>x2);
00,047             o1 = (x1>=x0)+(x1>x2);
00,048             o2 = (0+1+2)-(o0+o1);
00,049             QWORDS[TheMiddleOfMiddle+o0]=x0; QWORDS[TheMiddleOfMiddle+o1]=x1; QWORDS[TheMiddleOfMiddle+o2]=x2;
00,050             swapUnconditional (&QWORDS[TheMiddleOfMiddle+1], &QWORDS[PR]); //2nd
00,051 } else {
00,052             x3 = QWORDS[TheMiddleOfMiddle+3];
00,053             x4 = QWORDS[TheMiddleOfMiddle+4];
00,054             x5 = QWORDS[TheMiddleOfMiddle+5];
00,055             x6 = QWORDS[TheMiddleOfMiddle+6];
00,056             o0 = (x0>x1)+(x0>x2)+(x0>x3)+(x0>x4)+(x0>x5)+(x0>x6);
00,057             o1 = (x1>=x0)+(x1>x2)+(x1>x3)+(x1>x4)+(x1>x5)+(x1>x6);
00,058             o2 = (x2>=x0)+(x2>=x1)+(x2>x3)+(x2>x4)+(x2>x5)+(x2>x6);
00,059             o3 = (x3>=x0)+(x3>=x1)+(x3>=x2)+(x3>x4)+(x3>x5)+(x3>x6);
00,060             o4 = (x4>=x0)+(x4>=x1)+(x4>=x2)+(x4>=x3)+(x4>x5)+(x4>x6);
00,061             o5 = (x5>=x0)+(x5>=x1)+(x5>=x2)+(x5>=x3)+(x5>=x4)+(x5>x6);
00,062             o6 = (0+1+2+3+4+5+6)-(o0+o1+o2+o3+o4+o5);
00,063             QWORDS[TheMiddleOfMiddle+o0]=x0; QWORDS[TheMiddleOfMiddle+o1]=x1; QWORDS[TheMiddleOfMiddle+o2]=x2; QWORDS[TheMiddleOfMiddle+o3]=x3; QWORDS[TheMiddleOfMiddle+o4]=x4; QWORDS[TheMiddleOfMiddle+o5]=x5; QWORDS[TheMiddleOfMiddle+o6]=x6;
00,064             swapUnconditional (&QWORDS[TheMiddleOfMiddle+3], &QWORDS[PR]); //4th
00,065 }
00,066             Pivot = QWORDS[PR];
00,067     #else
00,068             swapUnconditional (&QWORDS[(Left + Right)>>1], &QWORDS[PR]);
00,069             Pivot = QWORDS[PR];
00,070     #endif
00,071     #ifdef revision4
00,072             for (;PR < Jndx;) {
00,073                 PR = PR + 1;
00,074                 if (Pivot > QWORDS[PR]) {
00,075                     swapUnconditional (&QWORDS[PL], &QWORDS[PR]);
00,076                     PL = PL + 1;
00,077                 } else if (Pivot < QWORDS[PR]) {
00,078                     for (;Pivot < QWORDS[Jndx];) {
00,079                         Jndx = Jndx - 1;
00,080                     }
00,081                     if (PR < Jndx) swapUnconditional (&QWORDS[PR], &QWORDS[Jndx]);
00,082                     Jndx = Jndx - 1;
00,083                     PR = PR - 1;
00,084                 }
00,085             }
00,086     #endif
00,087             Jndx = PL - 1;
00,088             Indx = PR + 1;
00,089     #ifdef FinishWithInsertionSort
00,090             GearBox = ( maxSO((Right-Indx), (Jndx-Left)) > minSO((Right-Indx), (Jndx-Left))<<6 ); // same as MAX/MIN > 64, i.e. Gear=1 if we need Median of 7
00,091     #endif
00,092             if (Indx + InsertionsortTHRESHOLD < Right) { // still refusing to go (always) with the smaller partition first...
00,093                 StackPtr = StackPtr + 2;
00,094                 Stack[StackPtr - 1] = Indx;
00,095                 Stack[StackPtr] = Right;
00,096     #ifdef FinishWithInsertionSort
00,097                 StackPtr = StackPtr*(StackPtr + 2 <= StackEntries-1);  // StackPtr should be enforced FALSE; also, ensure the next 'push' above is sanctioned - the max index of Stack[] being 'StackEntries-1'
00,098                 Right = Right*(StackPtr + 2 <= StackEntries-1); // Left + InsertionsortTHRESHOLD < Right should be enforced FALSE:
00,099     #endif
00,100             }
00,101             Right = Jndx;
00,102         } //while (Left + InsertionsortTHRESHOLD < Right);
00,103     } while ( (StackPtr != 0) );
00,104     #ifdef FinishWithInsertionSort
00,105     for (Indx=LeftBackup+1; Indx <= RightBackup; Indx++) {
00,106         Jndx = Indx;
00,107         for (;Jndx >= 1;) {
00,108             if (QWORDS[Jndx-1] > QWORDS[Jndx]) swapUnconditional (&QWORDS[Jndx-1], &QWORDS[Jndx]); else break;
00,109             Jndx = Jndx - 1;
00,110         }
00,111     }
00,112     #endif
00,113 }
*/

// 380 lines scalar Assembly:
/*
00,001 ; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
00,002 ; mark_description "-S -Os";
00,003 
00,004 Quicksort_QB64_v7	PROC 
00,005 .B4.1::                         
00,006         push      rbx                                           
00,007         push      rsi                                           
00,008         push      rdi                                           
00,009         push      r12                                           
00,010         push      r13                                           
00,011         push      r14                                           
00,012         push      r15                                           
00,013         push      rbp                                           
00,014         mov       eax, 800152                                   
00,015         call      __chkstk                                      
00,016         sub       rsp, 800152                                   
00,017         mov       r13, rcx                                      
00,018         mov       QWORD PTR [800064+rsp], r8                    
00,019         xor       r14d, r14d                                    
00,020         mov       QWORD PTR [40+rsp], rdx                       
00,021         mov       QWORD PTR [56+rsp], rdx                       
00,022         mov       QWORD PTR [32+rsp], 2                         
00,023         mov       QWORD PTR [64+rsp], r8                        
00,024 .B4.2::                         
00,025         mov       rax, QWORD PTR [32+rsp]                       
00,026         mov       rdx, QWORD PTR [40+rsp+rax*8]                 
00,027         mov       r12, QWORD PTR [48+rsp+rax*8]                 
00,028         add       rax, -2                                       
00,029         mov       QWORD PTR [800040+rsp], rdx                   
00,030         mov       QWORD PTR [32+rsp], rax                       
00,031         lea       rcx, QWORD PTR [17+rdx]                       
00,032         mov       QWORD PTR [800072+rsp], rcx                   
00,033         cmp       r12, rcx                                      
00,034         jle       .B4.27        
00,035 .B4.3::                         
00,036         mov       QWORD PTR [800056+rsp], rdx                   
00,037         lea       rax, QWORD PTR [r13+rdx*8]                    
00,038         mov       QWORD PTR [800048+rsp], rax                   
00,039 .B4.4::                         
00,040         mov       r8, r12                                       
00,041         xor       eax, eax                                      
00,042         mov       rbp, QWORD PTR [800040+rsp]                   
00,043         sub       r8, rbp                                       
00,044         sar       r8, 2                                         
00,045         xor       edx, edx                                      
00,046         add       r8, rbp                                       
00,047         xor       r15d, r15d                                    
00,048         mov       rbx, QWORD PTR [800056+rsp]                   
00,049         mov       rdi, r12                                      
00,050         mov       QWORD PTR [800056+rsp], rbp                   
00,051         lea       rsi, QWORD PTR [rbp*8]                        
00,052         lea       rcx, QWORD PTR [r13+r8*8]                     
00,053         mov       r10, QWORD PTR [rcx]                          
00,054         mov       r11, QWORD PTR [8+rcx]                        
00,055         cmp       r10, r11                                      
00,056         mov       r9, QWORD PTR [16+rcx]                        
00,057         seta      al                                            
00,058         cmp       r10, r9                                       
00,059         seta      dl                                            
00,060         add       eax, edx                                      
00,061         xor       edx, edx                                      
00,062         cmp       r11, r10                                      
00,063         setae     dl                                            
00,064         cmp       r11, r9                                       
00,065         seta      r15b                                          
00,066         add       edx, r15d                                     
00,067         test      r14d, r14d                                    
00,068         jne       .B4.6         
00,069 .B4.5::                         
00,070         add       rcx, 8                                        
00,071         lea       r14, QWORD PTR [r8+rax]                       
00,072         mov       QWORD PTR [r13+r14*8], r10                    
00,073         lea       r10, QWORD PTR [r8+rdx]                       
00,074         sub       r8, rax                                       
00,075         sub       r8, rdx                                       
00,076         mov       QWORD PTR [r13+r10*8], r11                    
00,077         mov       QWORD PTR [24+r13+r8*8], r9                   
00,078         jmp       .B4.7         
00,079 .B4.6::                         
00,080         mov       QWORD PTR [800104+rsp], rsi                   
00,081         xor       r14d, r14d                                    
00,082         mov       rsi, QWORD PTR [24+rcx]                       
00,083         cmp       r10, rsi                                      
00,084         mov       QWORD PTR [800096+rsp], rdi                   
00,085         mov       rdi, QWORD PTR [32+rcx]                       
00,086         seta      r14b                                          
00,087         xor       r15d, r15d                                    
00,088         cmp       r10, rdi                                      
00,089         mov       QWORD PTR [800088+rsp], r12                   
00,090         push      0                                             
00,091         pop       r12                                           
00,092         seta      r12b                                          
00,093         mov       QWORD PTR [800112+rsp], rbp                   
00,094         add       r14d, r12d                                    
00,095         mov       rbp, QWORD PTR [40+rcx]                       
00,096         xor       r12d, r12d                                    
00,097         cmp       r10, rbp                                      
00,098         mov       QWORD PTR [800120+rsp], rbx                   
00,099         seta      r12b                                          
00,100         mov       rbx, QWORD PTR [48+rcx]                       
00,101         cmp       r10, rbx                                      
00,102         mov       QWORD PTR [800080+rsp], rcx                   
00,103         push      0                                             
00,104         pop       rcx                                           
00,105         seta      cl                                            
00,106         add       eax, r14d                                     
00,107         add       r12d, ecx                                     
00,108         xor       ecx, ecx                                      
00,109         cmp       r11, rsi                                      
00,110         seta      cl                                            
00,111         xor       r14d, r14d                                    
00,112         cmp       r11, rdi                                      
00,113         seta      r15b                                          
00,114         cmp       r11, rbp                                      
00,115         seta      r14b                                          
00,116         add       eax, r12d                                     
00,117         xor       r12d, r12d                                    
00,118         cmp       r11, rbx                                      
00,119         seta      r12b                                          
00,120         add       ecx, r15d                                     
00,121         add       edx, ecx                                      
00,122         xor       ecx, ecx                                      
00,123         cmp       r9, r10                                       
00,124         setae     cl                                            
00,125         xor       r15d, r15d                                    
00,126         add       r14d, r12d                                    
00,127         xor       r12d, r12d                                    
00,128         cmp       r9, r11                                       
00,129         setae     r12b                                          
00,130         add       edx, r14d                                     
00,131         add       ecx, r12d                                     
00,132         xor       r12d, r12d                                    
00,133         cmp       r9, rsi                                       
00,134         seta      r12b                                          
00,135         xor       r14d, r14d                                    
00,136         cmp       r9, rdi                                       
00,137         seta      r15b                                          
00,138         add       r12d, r15d                                    
00,139         xor       r15d, r15d                                    
00,140         add       ecx, r12d                                     
00,141         xor       r12d, r12d                                    
00,142         cmp       r9, rbp                                       
00,143         seta      r12b                                          
00,144         cmp       r9, rbx                                       
00,145         seta      r14b                                          
00,146         cmp       rsi, r10                                      
00,147         setae     r15b                                          
00,148         add       r12d, r14d                                    
00,149         xor       r14d, r14d                                    
00,150         cmp       rsi, r11                                      
00,151         setae     r14b                                          
00,152         add       ecx, r12d                                     
00,153         add       r15d, r14d                                    
00,154         xor       r14d, r14d                                    
00,155         cmp       rsi, r9                                       
00,156         setae     r14b                                          
00,157         xor       r12d, r12d                                    
00,158         cmp       rsi, rdi                                      
00,159         seta      r12b                                          
00,160         add       r14d, r12d                                    
00,161         xor       r12d, r12d                                    
00,162         add       r15d, r14d                                    
00,163         xor       r14d, r14d                                    
00,164         cmp       rsi, rbp                                      
00,165         seta      r14b                                          
00,166         cmp       rsi, rbx                                      
00,167         seta      r12b                                          
00,168         add       r14d, r12d                                    
00,169         xor       r12d, r12d                                    
00,170         add       r15d, r14d                                    
00,171         xor       r14d, r14d                                    
00,172         cmp       rdi, r10                                      
00,173         setae     r14b                                          
00,174         cmp       rdi, r11                                      
00,175         setae     r12b                                          
00,176         add       r14d, r12d                                    
00,177         xor       r12d, r12d                                    
00,178         cmp       rdi, r9                                       
00,179         setae     r12b                                          
00,180         cmp       rdi, rsi                                      
00,181         mov       QWORD PTR [800128+rsp], r15                   
00,182         push      0                                             
00,183         pop       r15                                           
00,184         setae     r15b                                          
00,185         add       r12d, r15d                                    
00,186         xor       r15d, r15d                                    
00,187         add       r14d, r12d                                    
00,188         xor       r12d, r12d                                    
00,189         cmp       rdi, rbp                                      
00,190         seta      r12b                                          
00,191         cmp       rdi, rbx                                      
00,192         seta      r15b                                          
00,193         add       r12d, r15d                                    
00,194         xor       r15d, r15d                                    
00,195         add       r14d, r12d                                    
00,196         xor       r12d, r12d                                    
00,197         cmp       rbp, r10                                      
00,198         setae     r12b                                          
00,199         cmp       rbp, r11                                      
00,200         setae     r15b                                          
00,201         add       r12d, r15d                                    
00,202         xor       r15d, r15d                                    
00,203         cmp       rbp, r9                                       
00,204         setae     r15b                                          
00,205         cmp       rbp, rsi                                      
00,206         mov       QWORD PTR [800136+rsp], r14                   
00,207         push      0                                             
00,208         pop       r14                                           
00,209         setae     r14b                                          
00,210         add       r15d, r14d                                    
00,211         xor       r14d, r14d                                    
00,212         add       r12d, r15d                                    
00,213         xor       r15d, r15d                                    
00,214         cmp       rbp, rdi                                      
00,215         setae     r15b                                          
00,216         cmp       rbp, rbx                                      
00,217         seta      r14b                                          
00,218         add       r15d, r14d                                    
00,219         lea       r14, QWORD PTR [r8+rax]                       
00,220         mov       QWORD PTR [r13+r14*8], r10                    
00,221         lea       r10, QWORD PTR [r8+rdx]                       
00,222         mov       QWORD PTR [r13+r10*8], r11                    
00,223         lea       r11, QWORD PTR [r8+rcx]                       
00,224         mov       r10, QWORD PTR [800128+rsp]                   
00,225         add       r12d, r15d                                    
00,226         mov       QWORD PTR [r13+r11*8], r9                     
00,227         add       rcx, r10                                      
00,228         mov       r11, QWORD PTR [800136+rsp]                   
00,229         lea       r9, QWORD PTR [r8+r10]                        
00,230         mov       QWORD PTR [r13+r9*8], rsi                     
00,231         lea       rsi, QWORD PTR [r8+r11]                       
00,232         add       r11, r12                                      
00,233         mov       QWORD PTR [r13+rsi*8], rdi                    
00,234         add       rcx, r11                                      
00,235         mov       rsi, QWORD PTR [800104+rsp]                   
00,236         lea       rdi, QWORD PTR [r8+r12]                       
00,237         sub       r8, rax                                       
00,238         sub       r8, rdx                                       
00,239         sub       r8, rcx                                       
00,240         mov       QWORD PTR [r13+rdi*8], rbp                    
00,241         mov       rcx, QWORD PTR [800080+rsp]                   
00,242         mov       rbp, QWORD PTR [800112+rsp]                   
00,243         add       rcx, 24                                       
00,244         mov       QWORD PTR [168+r13+r8*8], rbx                 
00,245         mov       rbx, QWORD PTR [800120+rsp]                   
00,246         mov       rdi, QWORD PTR [800096+rsp]                   
00,247         mov       r12, QWORD PTR [800088+rsp]                   
00,248 .B4.7::                         
00,249         mov       rdx, QWORD PTR [800048+rsp]                   
00,250         call      swapUnconditional                             
00,251 .B4.8::                         
00,252         mov       rax, QWORD PTR [800048+rsp]                   
00,253         cmp       r12, QWORD PTR [800040+rsp]                   
00,254         mov       r14, QWORD PTR [rax]                          
00,255         jle       .B4.23        
00,256 .B4.10::                        
00,257         inc       rbp                                           
00,258         lea       rdx, QWORD PTR [r13+rbp*8]                    
00,259         cmp       r14, QWORD PTR [rdx]                          
00,260         jbe       .B4.13        
00,261 .B4.11::                        
00,262         lea       rcx, QWORD PTR [r13+rsi]                      
00,263         call      swapUnconditional                             
00,264 .B4.12::                        
00,265         add       rsi, 8                                        
00,266         inc       rbx                                           
00,267         jmp       .B4.21        
00,268 .B4.13::                        
00,269         jae       .B4.21        
00,270 .B4.14::                        
00,271         lea       rax, QWORD PTR [r13+rdi*8]                    
00,272         cmp       r14, QWORD PTR [rax]                          
00,273         jae       .B4.18        
00,274 .B4.16::                        
00,275         dec       rdi                                           
00,276         lea       rax, QWORD PTR [r13+rdi*8]                    
00,277         cmp       r14, QWORD PTR [rax]                          
00,278         jb        .B4.16        
00,279 .B4.18::                        
00,280         cmp       rbp, rdi                                      
00,281         jge       .B4.20        
00,282 .B4.19::                        
00,283         mov       rcx, rdx                                      
00,284         mov       rdx, rax                                      
00,285         call      swapUnconditional                             
00,286 .B4.20::                        
00,287         dec       rdi                                           
00,288         dec       rbp                                           
00,289 .B4.21::                        
00,290         cmp       rbp, rdi                                      
00,291         jl        .B4.10        
00,292 .B4.23::                        
00,293         dec       rbx                                           
00,294         lea       r9, QWORD PTR [1+rbp]                         
00,295         mov       rdi, r12                                      
00,296         mov       r8, rbx                                       
00,297         sub       r8, QWORD PTR [800040+rsp]                    
00,298         sub       rdi, r9                                       
00,299         xor       edx, edx                                      
00,300         cmp       rdi, r8                                       
00,301         mov       rcx, rdi                                      
00,302         setl      dl                                            
00,303         xor       r14d, r14d                                    
00,304         xor       rcx, r8                                       
00,305         neg       edx                                           
00,306         add       rbp, 18                                       
00,307         movsxd    rdx, edx                                      
00,308         and       rcx, rdx                                      
00,309         xor       r8, rcx                                       
00,310         xor       rdi, rcx                                      
00,311         shl       r8, 6                                         
00,312         cmp       rdi, r8                                       
00,313         setg      r14b                                          
00,314         cmp       r12, rbp                                      
00,315         jle       .B4.25        
00,316 .B4.24::                        
00,317         mov       rax, QWORD PTR [32+rsp]                       
00,318         cmp       rax, 99994                                    
00,319         mov       QWORD PTR [64+rsp+rax*8], r12                 
00,320         push      0                                             
00,321         pop       r12                                           
00,322         setle     r12b                                          
00,323         mov       QWORD PTR [56+rsp+rax*8], r9                  
00,324         add       rax, 2                                        
00,325         imul      rax, r12                                      
00,326         mov       QWORD PTR [32+rsp], rax                       
00,327 .B4.25::                        
00,328         mov       r12, rbx                                      
00,329         cmp       rbx, QWORD PTR [800072+rsp]                   
00,330         jg        .B4.4         
00,331 .B4.27::                        
00,332         cmp       QWORD PTR [32+rsp], 0                         
00,333         jne       .B4.2         
00,334 .B4.28::                        
00,335         mov       rax, QWORD PTR [40+rsp]                       
00,336         inc       rax                                           
00,337         mov       QWORD PTR [40+rsp], rax                       
00,338         cmp       rax, QWORD PTR [800064+rsp]                   
00,339         jg        .B4.39        
00,340 .B4.30::                        
00,341         mov       rbx, QWORD PTR [40+rsp]                       
00,342         test      rbx, rbx                                      
00,343         jle       .B4.28        
00,344 .B4.32::                        
00,345         mov       rax, QWORD PTR [-8+r13+rbx*8]                 
00,346         cmp       rax, QWORD PTR [r13+rbx*8]                    
00,347         jbe       .B4.28        
00,348 .B4.33::                        
00,349         lea       rdx, QWORD PTR [r13+rbx*8]                    
00,350         lea       rcx, QWORD PTR [-8+rdx]                       
00,351         call      swapUnconditional                             
00,352 .B4.34::                        
00,353         dec       rbx                                           
00,354         test      rbx, rbx                                      
00,355         jg        .B4.32        
00,356         jmp       .B4.28        
00,357 .B4.39::                        
00,358         add       rsp, 800152                                   
00,359         pop       rbp                                           
00,360         pop       r15                                           
00,361         pop       r14                                           
00,362         pop       r13                                           
00,363         pop       r12                                           
00,364         pop       rdi                                           
00,365         pop       rsi                                           
00,366         pop       rbx                                           
00,367         ret                                                     
00,368 .B4.40::
00,369 Quicksort_QB64_v7 ENDP
00,370 
00,371 swapUnconditional	PROC 
00,372 .B5.1::                         
00,373         mov       rax, QWORD PTR [rdx]                          
00,374         mov       r8, QWORD PTR [rcx]                           
00,375         mov       QWORD PTR [rcx], rax                          
00,376         mov       QWORD PTR [rdx], r8                           
00,377 .B5.4::                         
00,378         ret                                                     
00,379 .B5.2::
00,380 swapUnconditional ENDP
*/


// Quicksort 'Magnetica' r.6, unbreakable (never overflowing the stack) when '#define FinishWithInsertionSort' is uncommented [
// We have two revisions - r.5BB and r.5FF, standing respectively for Bare-Bone (Pure Quicksort) and Full-Fledged (Fallbacks to Insertionsort).
// If below define is commented then we have "middle Pivot standalone Magnetica", otherwise "median of 3/7 Pivot InsertionSort Magnetica".
// Provide below flag via command line: -DFinishWithInsertionSort
//#define FinishWithInsertionSort
// Roughly speaking:
// - with (median of 1) nastiest quadratic O((N/1)^2) we have 2(N/1) (due to Left+Right=2, a pair) stack usage;
// - with (median of 3) less nastier quadratic O((N/2)^2) we have 2(N/2) (due to Left+Right=2, a pair) stack usage;
// - with (median of 5) even less nastier quadratic O((N/3)^2) we have 2(N/3) (due to Left+Right=2, a pair) stack usage;
// - with (median of 7) even more less nastier quadratic O((N/4)^2) we have 2(N/4) (due to Left+Right=2, a pair) stack usage;
// Value below allows 2(N/4)= 2((Right-Left+1)/4) = (99999-1) i.e. N=2(99999-1) or ~200,000 elements
#define StackEntries 99999
// Uncomment either 4 (fastest so far) or 3 (for reference only):
//#define revision6
#define revision5
//#define revision4
//#define revision3
// Thus we have 4 variants:
// Variant #1: "middle Pivot standalone Magnetica r.4"
// Variant #2: "middle Pivot standalone Magnetica r.3"
// Variant #3: "median of 3/7 Pivot InsertionSort Magnetica r.4"
// Variant #4: "median of 3/7 Pivot InsertionSort Magnetica r.3"
void swapUnconditional(uint64_t *a, uint64_t *b) { uint64_t t = *a; *a = *b; *b = t; }
uint64_t sex(int64_t x) { return x >> (8*sizeof(uint64_t)-1); }
uint64_t minKaze(uint64_t a, uint64_t b) { return b + ((a-b) & sex(a-b)); }
uint64_t maxKaze(uint64_t a, uint64_t b) { return a + ((b-a) & ~sex(b-a)); }
// Many thanks go to all the coders at: https://stackoverflow.com/questions/2786899/fastest-sort-of-fixed-length-6-int-array
#define minSO(x, y) (y ^ ((x ^ y) & -(x < y)))
#define maxSO(x, y) (x ^ ((x ^ y) & -(x < y)))
//    _____                                __  .__               
//   /     \ _____     ____   ____   _____/  |_|__| ____ _____   
//  /  \ /  \\__  \   / ___\ /    \_/ __ \   __\  |/ ___\\__  \  
// /    Y    \/ __ \_/ /_/  >   |  \  ___/|  | |  \  \___ / __ \_
// \____|__  (____  /\___  /|___|  /\___  >__| |__|\___  >____  /
//         \/     \//_____/      \/     \/             \/     \/ 
// Written by Sanmayce, 2022-Feb-26
// The indexes are signed, but the elements are unsigned, targeting 64bit pointers mostly.
void swapConditionalXY_Akkodah(uint64_t X, uint64_t Y, uint64_t *a, uint64_t *b) { int64_t XYsgnd = -(X<Y); int64_t ABsgnd= *a-*b; ABsgnd = ABsgnd&XYsgnd; *a = *a-ABsgnd; *b = *b+ABsgnd; } // if X<Y then swap
void swapConditionalXY_BUGGY(uint64_t X, uint64_t Y, uint64_t *a, uint64_t *b) { int64_t XYsgnd = X-Y; int64_t ABsgnd= *a-*b; ABsgnd = ABsgnd&(XYsgnd >> 63); *a = *a-ABsgnd; *b = *b+ABsgnd; } // if X<Y then swap
/*
swapConditionalXY_BUGGY	PROC 
; parameter 1: rcx
; parameter 2: rdx
; parameter 3: r8
; parameter 4: r9

;;; void swapConditionalXY_BUGGY(uint64_t X, uint64_t Y, uint64_t *a, uint64_t *b) { int64_t XYsgnd = X-Y; int64_t ABsgnd= *a-*b; ABsgnd = ABsgnd&(XYsgnd >> 63); *a = *a-ABsgnd; *b = *b+ABsgnd; } // if X<Y then swap

  00000 48 2b ca         sub rcx, rdx                           
  00003 4d 8b 11         mov r10, QWORD PTR [r9]                
  00006 49 f7 da         neg r10                                
  00009 49 8b 00         mov rax, QWORD PTR [r8]                
  0000c 4c 03 d0         add r10, rax                           
  0000f 48 c1 f9 3f      sar rcx, 63                            
  00013 4c 23 d1         and r10, rcx                           
  00016 49 2b c2         sub rax, r10                           
  00019 49 89 00         mov QWORD PTR [r8], rax                
  0001c 4d 01 11         add QWORD PTR [r9], r10                
*/
//void swapConditionalXYinc(uint64_t X, uint64_t Y, uint64_t *a, uint64_t *b, uint64_t *PL) { int64_t XYsgnd = -(X<Y); int64_t ABsgnd= *a-*b; ABsgnd = ABsgnd&XYsgnd; *a = *a-ABsgnd; *b = *b+ABsgnd; *PL = *PL-XYsgnd; } // if X<Y then swap
void Quicksort_QB64_v10(uint64_t QWORDS[], int64_t Left, int64_t Right) {
    #ifdef FinishWithInsertionSort
    int InsertionsortTHRESHOLD = 13;
    #else
    int InsertionsortTHRESHOLD = 0;
    #endif
    int64_t Indx, Jndx, PL, PR;
    int64_t Stack[StackEntries];
    int64_t StackPtr = 0;
    uint64_t Pivot;
    int64_t LeftBackup = Left;
    int64_t RightBackup = Right;
    register uint64_t x0,x1,x2,x3,x4,x5,x6;
    int o0,o1,o2,o3,o4,o5,o6;
    int64_t TheMiddleOfMiddle;
    int Stefan_Edelkamp_Armin_Weiss1, Stefan_Edelkamp_Armin_Weiss2, Stefan_Edelkamp_Armin_Weiss3;
    uint64_t tmp;
    int GearBox = 0; // 0 is Median of 3; 1 is Median of 7; Shifting to higher gear if BiggerPartition:SmallerPartition ratio is > 64:1
    StackPtr++; Stack[StackPtr] = Left;
    StackPtr++; Stack[StackPtr] = Right;
    do {
        Right = Stack[StackPtr];
        Left = Stack[StackPtr - 1];
        StackPtr = StackPtr - 2;
        //do {
        for(;(Left + InsertionsortTHRESHOLD < Right);) { // For instance, 1 + 17 < 19 i.e. (19-1)/4+6 < 19
            Jndx = Right;
            PL = Left;
            PR = Left;
    #ifdef FinishWithInsertionSort
            TheMiddleOfMiddle = Left + ((Right-Left)>>2); // (4Left + Right - Left)/4; Caution: [TheMiddleOfMiddle+6] should be <= [Right] i.e. 6+(4Left + Right - Left)/4 <= Right or 4*6+(4Left + Right - Left) <= 4Right or 4*6 <= 3Right-3Left or (4*6)/3 <= Right-Left i.e. 8 <= Right-Left as a minimum condition to enter the 'for'.
            x0 = QWORDS[TheMiddleOfMiddle+0];
            x1 = QWORDS[TheMiddleOfMiddle+1];
            x2 = QWORDS[TheMiddleOfMiddle+2];
if (GearBox == 0) { // Median of 5 proves more effective than 7, however 7 betters better the nastiest N^2
            o0 = (x0>x1)+(x0>x2);
            o1 = (x1>=x0)+(x1>x2);
            o2 = (0+1+2)-(o0+o1);
            QWORDS[TheMiddleOfMiddle+o0]=x0; QWORDS[TheMiddleOfMiddle+o1]=x1; QWORDS[TheMiddleOfMiddle+o2]=x2;
            swapUnconditional (&QWORDS[TheMiddleOfMiddle+1], &QWORDS[PR]); //2nd
} else {
            x3 = QWORDS[TheMiddleOfMiddle+3];
            x4 = QWORDS[TheMiddleOfMiddle+4];
            x5 = QWORDS[TheMiddleOfMiddle+5];
            x6 = QWORDS[TheMiddleOfMiddle+6];
            o0 = (x0>x1)+(x0>x2)+(x0>x3)+(x0>x4)+(x0>x5)+(x0>x6);
            o1 = (x1>=x0)+(x1>x2)+(x1>x3)+(x1>x4)+(x1>x5)+(x1>x6);
            o2 = (x2>=x0)+(x2>=x1)+(x2>x3)+(x2>x4)+(x2>x5)+(x2>x6);
            o3 = (x3>=x0)+(x3>=x1)+(x3>=x2)+(x3>x4)+(x3>x5)+(x3>x6);
            o4 = (x4>=x0)+(x4>=x1)+(x4>=x2)+(x4>=x3)+(x4>x5)+(x4>x6);
            o5 = (x5>=x0)+(x5>=x1)+(x5>=x2)+(x5>=x3)+(x5>=x4)+(x5>x6);
            o6 = (0+1+2+3+4+5+6)-(o0+o1+o2+o3+o4+o5);
            QWORDS[TheMiddleOfMiddle+o0]=x0; QWORDS[TheMiddleOfMiddle+o1]=x1; QWORDS[TheMiddleOfMiddle+o2]=x2; QWORDS[TheMiddleOfMiddle+o3]=x3; QWORDS[TheMiddleOfMiddle+o4]=x4; QWORDS[TheMiddleOfMiddle+o5]=x5; QWORDS[TheMiddleOfMiddle+o6]=x6;
            swapUnconditional (&QWORDS[TheMiddleOfMiddle+3], &QWORDS[PR]); //4th
}
            Pivot = QWORDS[PR];
    #else
            swapUnconditional (&QWORDS[(Left + Right)>>1], &QWORDS[PR]);
            Pivot = QWORDS[PR];
    #endif

/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; mark_description "-FAcs -O3 -FeQS_bench_r9+_ICL15.0_64bit.exe -D_N_HIGH_PRIORITY";
; b3-66+2=79 bytes, 3/1 conditional/unconditional jumps; 24 instructions
; 'Magnetica' partitioning, mainloop rev.6[
.B66.5::                        
  00066 49 ff c5         inc r13                                
  00069 4e 8b 14 e9      mov r10, QWORD PTR [rcx+r13*8]         
  0006d 4d 3b c2         cmp r8, r10                            
  00070 77 2f            ja .B66.10 
.B66.6::                        
  00072 73 3c            jae .B66.11 
.B66.7::                        
  00074 41 be 01 00 00 
        00               mov r14d, 1                            
.B66.8::                        
  0007a 45 33 ff         xor r15d, r15d                         
  0007d 4e 3b 04 d9      cmp r8, QWORD PTR [rcx+r11*8]          
  00081 4d 0f 42 fe      cmovb r15, r14                         
  00085 4d 2b df         sub r11, r15                           
  00088 4d 85 ff         test r15, r15                          
  0008b 75 ed            jne .B66.8 
.B66.9::                        
  0008d 4e 8b 34 d9      mov r14, QWORD PTR [rcx+r11*8]         
  00091 4e 89 34 e9      mov QWORD PTR [rcx+r13*8], r14         
  00095 49 ff cd         dec r13                                
  00098 4e 89 14 d9      mov QWORD PTR [rcx+r11*8], r10         
  0009c 49 ff cb         dec r11                                
  0009f eb 0f            jmp .B66.11 
.B66.10::                       
  000a1 4c 8b 34 e9      mov r14, QWORD PTR [rcx+rbp*8]         
  000a5 4c 89 14 e9      mov QWORD PTR [rcx+rbp*8], r10         
  000a9 48 ff c5         inc rbp                                
  000ac 4e 89 34 e9      mov QWORD PTR [rcx+r13*8], r14         
.B66.11::                       
  000b0 4d 3b eb         cmp r13, r11                           
  000b3 7c b1            jl .B66.5 
; 'Magnetica' partitioning, mainloop rev.6]
*/

    #ifdef revision6
            for (;PR < Jndx;) {
                PR = PR + 1;
                if (Pivot > QWORDS[PR]) {
                    swapUnconditional (&QWORDS[PL], &QWORDS[PR]);
                    PL = PL + 1;
                //} else if (Pivot == QWORDS[PR]) {
                } else if (Pivot < QWORDS[PR]) {
Nasty:
                    Stefan_Edelkamp_Armin_Weiss1 = (Pivot < QWORDS[Jndx]);
                    Jndx = Jndx - Stefan_Edelkamp_Armin_Weiss1;
if (Stefan_Edelkamp_Armin_Weiss1) goto Nasty;
                    //for (;Pivot < QWORDS[Jndx];) {
                    //    Jndx = Jndx - 1;
                    //}
                    swapUnconditional (&QWORDS[PR], &QWORDS[Jndx]); // Magnetica r.5
                    //if (PR < Jndx) swapUnconditional (&QWORDS[PR], &QWORDS[Jndx]);
                    //swapConditionalXY_BUGGY(PR, Jndx, &QWORDS[PR], &QWORDS[Jndx]); // Should be faster than "Akkodah" but buggy when wraparounding, inhere 'PR' and 'Jndx' are far below the dangerous values - no pitfall.
                    //swapConditionalXY_Akkodah(PR, Jndx, &QWORDS[PR], &QWORDS[Jndx]); // The safe one, but slower, isn't it?!
                    Jndx = Jndx - 1;
                    PR = PR - 1;
                }
            }
            if (PR > Jndx) { //redeem i.e. undo
                    swapUnconditional (&QWORDS[PR+1], &QWORDS[Jndx+1]);
            }
    #endif


/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; mark_description "-FAcs -O3 -FeQS_bench_r9+_ICL15.0_64bit.exe -D_N_HIGH_PRIORITY";
; aa-65+2=71 bytes, 4/1 conditional/unconditional jumps; 23 instructions
; 'Magnetica' partitioning, mainloop rev.5[
.B66.5::                        
  00065 49 ff c6         inc r14                                
  00068 4e 8b 14 f1      mov r10, QWORD PTR [rcx+r14*8]         
  0006c 4d 3b c2         cmp r8, r10                            
  0006f 77 27            ja .B66.12 
.B66.6::                        
  00071 73 34            jae .B66.13 
.B66.7::                        
  00073 4e 8b 3c d9      mov r15, QWORD PTR [rcx+r11*8]         
  00077 4d 3b c7         cmp r8, r15                            
  0007a 73 0c            jae .B66.11 
.B66.9::                        
  0007c 49 ff cb         dec r11                                
  0007f 4e 8b 3c d9      mov r15, QWORD PTR [rcx+r11*8]         
  00083 4d 3b c7         cmp r8, r15                            
  00086 72 f4            jb .B66.9 
.B66.11::                       
  00088 4e 89 3c f1      mov QWORD PTR [rcx+r14*8], r15         
  0008c 49 ff ce         dec r14                                
  0008f 4e 89 14 d9      mov QWORD PTR [rcx+r11*8], r10         
  00093 49 ff cb         dec r11                                
  00096 eb 0f            jmp .B66.13 
.B66.12::                       
  00098 4c 8b 3c e9      mov r15, QWORD PTR [rcx+rbp*8]         
  0009c 4c 89 14 e9      mov QWORD PTR [rcx+rbp*8], r10         
  000a0 48 ff c5         inc rbp                                
  000a3 4e 89 3c f1      mov QWORD PTR [rcx+r14*8], r15         
.B66.13::                       
  000a7 4d 3b f3         cmp r14, r11                           
  000aa 7c b9            jl .B66.5 
; 'Magnetica' partitioning, mainloop rev.5]
*/

    #ifdef revision5
            for (;PR < Jndx;) {
                PR = PR + 1;
                if (Pivot > QWORDS[PR]) {
                    swapUnconditional (&QWORDS[PL], &QWORDS[PR]);
                    PL = PL + 1;
                //} else if (Pivot == QWORDS[PR]) {
                } else if (Pivot < QWORDS[PR]) {
                    for (;Pivot < QWORDS[Jndx];) {
                        Jndx = Jndx - 1;
                    }
                    swapUnconditional (&QWORDS[PR], &QWORDS[Jndx]); // Magnetica r.5
                    //if (PR < Jndx) swapUnconditional (&QWORDS[PR], &QWORDS[Jndx]);
                    //swapConditionalXY_BUGGY(PR, Jndx, &QWORDS[PR], &QWORDS[Jndx]); // Should be faster than "Akkodah" but buggy when wraparounding, inhere 'PR' and 'Jndx' are far below the dangerous values - no pitfall.
                    //swapConditionalXY_Akkodah(PR, Jndx, &QWORDS[PR], &QWORDS[Jndx]); // The safe one, but slower, isn't it?!
                    Jndx = Jndx - 1;
                    PR = PR - 1;
                }
            }
            if (PR > Jndx) { //redeem i.e. undo
                    swapUnconditional (&QWORDS[PR+1], &QWORDS[Jndx+1]);
            }
    #endif

// Test run: 2022-Feb-27:
// Laptop "Compressionette", Intel 'Kaby Lake' i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz:
// +--------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// | Performer/Keys     | FEW distinct              | MANY distinct             | ALL distinct              | ALLmore distinct           | ALLmax distinct             |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// |  Operating System, | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,   | Windows 10,  | Fedora 35,   |
// |      Compiler, -O3 | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1   | Intel v15.0  | GCC 11.2.1   |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | qsort              |  60 seconds | 412 seconds | 350 seconds | 565 seconds | 450 seconds | 551 seconds | 881 seconds | 1066 seconds |         N.A. |         N.A. |
// | Bentley-McIlroy    |  38 seconds |  40 seconds | 204 seconds | 220 seconds | 276 seconds | 296 seconds | 542 seconds |  582 seconds |         N.A. |         N.A. |
// | Magnetica r.5BB    |  31 seconds |  33 seconds | 204 seconds | 216 seconds | 272 seconds | 286 seconds | 537 seconds |  565 seconds |         N.A. |         N.A. |
// | Magnetica r.5FF    |  32 seconds |  38 seconds | 209 seconds | 239 seconds | 265 seconds | 319 seconds | 525 seconds |  625 seconds |         N.A. |         N.A. |
// | Fluxsort           |  38 seconds |  38 seconds | 137 seconds | 138 seconds | 256 seconds | 197 seconds | 933 seconds |  641 seconds |         N.A. |         N.A. |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | Best Time (bare    |                           |                           |                           |                            |                             |
// | bone in-place QS): |  31s for Magnetica r.5BB  | 204s PARITY               | 272s for Magnetica r.5BB  | 537s for Magnetica r.5BB   | N.A.                        |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+----------------------------+-----------------------------+
// Bottomline: Realistically - 3 wins out of 4 runs both for Magnetica vs qsort & Bentley-McIlroy, the rest is PARITY.
// Note: Scandum's Fluxsort is superior speedwise, but using out-of-place RAM is problematic when RAM is not sufficient, virtual trashing happens.
//
// Legend (The time is exactly the Sort process time):
// FEW = 2,233,861,800 keys, of them distinct = 10; 178,708,944 bytes 22338618_QWORDS.bin; elements = 178,708,944/8 *100; // Keys are 100 times duplicated
// MANY = 2,482,300,900 keys, of them distinct = 2,847,531; 24,823,016 bytes mobythesaurus.txt; elements = 24823016 -8+1; // BuildingBlocks are size-order+1, they are 100 times duplicated
// ALL = 2,009,333,753 keys, of them distinct = 1,912,608,132; 2,009,333,760 bytes Fedora-Workstation-Live-x86_64-35-1.2.iso; elements = 2009333760 -8+1; // BuildingBlocks are size-order+1
// ALLmore = 3,803,483,825 keys, of them distinct = 3,346,259,533; 3,803,483,832 bytes Fedora-Workstation-35-1.2.aarch64.raw.xz; elements = 3803483832 -8+1; // BuildingBlocks are size-order+1
// ALLmax = 7,798,235,435 keys, of them distinct = 6,770,144,405; 7,798,235,442 bytes math.stackexchange.com_en_all_2019-02.zim; elements = 7798235442 -8+1; // BuildingBlocks are size-order+1
// 
// Notes:
// - All the runs were in "Current priority class is REALTIME_PRIORITY_CLASS" for Windows and "Current priority is -20." for Linux;
// - Better speeds for Magnetica r.5FF with Insertionsort Threshold 13 instead of 31;
// - Benchmark needs 32GB RAM, and 64GB for the 5th testset;
// - The whole package (except the 3rd, 4th and 5th datasets) is downloadable at:
//   www.sanmayce.com/Quicksort_says_rev9+_finished 
// - To reproduce the roster, run on Windows or Linux:
//   - BENCH_ICL32GB.BAT
//   - BENCH_ICL64GB.BAT
//   - sh bench_gcc32GB.sh
//   - sh bench_gcc64GB.sh
// - 3rd dataset is downloadable at:
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso 
// - 4th dataset is downloadable at:
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/aarch64/images/Fedora-Workstation-35-1.2.aarch64.raw.xz 
// - 5th dataset is downloadable at:
// https://download.kiwix.org/zim/stack_exchange/math.stackexchange.com_en_all_2019-02.zim

// Note: Variant r.6 is much slower than r.5?! Didn't expect that.
// Note: When the "slower" variant r.5- (swapConditionalXY_BUGGY) was used, it was faster with ICL v.15.0, but was slower with GCC, so I commented it out. It has great potential if the elements are DWORDS i.e. 32bit, debranchifying awaits... a great sorter can be done...

// Laptop "Brutalitto", AMD 'Renoir' 4800H 4.3GHz max turbo, 64GB DDR4 3200MHz:
// +--------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// | Performer/Keys     | FEW distinct              | MANY distinct             | ALL distinct              | ALLmore distinct           | ALLmax distinct             |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// |  Operating System, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10,  | Windows 10,  | Windows 10,  |
// |      Compiler, -O3 | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1   | Intel v15.0  | GCC 11.2.1   |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | qsort              |  48 seconds |  45 seconds | 286 seconds | 282 seconds | 371 seconds | 366 seconds | 724 seconds |  714 seconds | 1505 seconds | 1497 seconds |
// | Bentley-McIlroy    |  24 seconds |  25 seconds | 148 seconds | 143 seconds | 202 seconds | 195 seconds | 393 seconds |  381 seconds |  888 seconds |  832 seconds |
// | Magnetica r.5BB    |  22 seconds |  24 seconds | 144 seconds | 152 seconds | 195 seconds | 206 seconds | 380 seconds |  403 seconds |  818 seconds |  852 seconds |
// | Magnetica r.5FF    |  25 seconds |  25 seconds | 158 seconds | 158 seconds | 205 seconds | 243 seconds | 403 seconds |  478 seconds |  972 seconds |  987 seconds |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | Best Time:         |  22s for Magnetica r.5BB  | 143s for Bentley-McIlroy  | 195s PARITY               | 380s for Magnetica r.5BB   |  818s for Magnetica r.5BB   |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+----------------------------+-----------------------------+
// Bottomline: Realistically - 2 wins out of 5 runs, the rest 3 are PARITY.
//
// Laptop "Compressionette", Intel 'Kaby Lake' i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz:
// +--------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// | Performer/Keys     | FEW distinct              | MANY distinct             | ALL distinct              | ALLmore distinct           | ALLmax distinct             |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// |  Operating System, | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,   | Windows 10,  | Fedora 35,   |
// |      Compiler, -O3 | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1   | Intel v15.0  | GCC 11.2.1   |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | qsort              |  62 seconds | 387 seconds | 372 seconds | 553 seconds | 474 seconds | 529 seconds | 927 seconds | 1034 seconds |         N.A. |         N.A. |
// | Bentley-McIlroy    |  37 seconds |  40 seconds | 202 seconds | 219 seconds | 275 seconds | 295 seconds | 538 seconds |  580 seconds |         N.A. |         N.A. |
// | Magnetica r.5BB    |  32 seconds |  34 seconds | 215 seconds | 218 seconds | 285 seconds | 289 seconds | 561 seconds |  571 seconds |         N.A. |         N.A. |
// | Magnetica r.5FF    |  34 seconds |  39 seconds | 215 seconds | 240 seconds | 274 seconds | 343 seconds | 539 seconds |  673 seconds |         N.A. |         N.A. |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | Best Time:         |  32s for Magnetica r.5BB  | 202s for Bentley-McIlroy  | 274s for Magnetica r.5FF  | 538s for Bentley-McIlroy   | N.A.                        |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+----------------------------+-----------------------------+
// Bottomline: Realistically - 1 win out of 4 runs both for Magnetica and Bentley-McIlroy, the rest 2 are PARITY.
//
// Legend (The time is exactly the Sort process time):
// FEW = 2,233,861,800 keys, of them distinct = 10; 178,708,944 bytes 22338618_QWORDS.bin; elements = 178,708,944/8 *100; // Keys are 100 times duplicated
// MANY = 2,482,300,900 keys, of them distinct = 2,847,531; 24,823,016 bytes mobythesaurus.txt; elements = 24823016 -8+1; // BuildingBlocks are size-order+1, they are 100 times duplicated
// ALL = 2,009,333,753 keys, of them distinct = 1,912,608,132; 2,009,333,760 bytes Fedora-Workstation-Live-x86_64-35-1.2.iso; elements = 2009333760 -8+1; // BuildingBlocks are size-order+1
// ALLmore = 3,803,483,825 keys, of them distinct = 3,346,259,533; 3,803,483,832 bytes Fedora-Workstation-35-1.2.aarch64.raw.xz; elements = 3803483832 -8+1; // BuildingBlocks are size-order+1
// ALLmax = 7,798,235,435 keys, of them distinct = 6,770,144,405; 7,798,235,442 bytes math.stackexchange.com_en_all_2019-02.zim; elements = 7798235442 -8+1; // BuildingBlocks are size-order+1
// 
// Notes:
// - All the runs were in "Current priority class is REALTIME_PRIORITY_CLASS" for Windows and "Current priority is -20." for Linux;
// - Benchmark needs 32GB RAM, and 64GB for the 5th testset;
// - The whole package (except the 3rd, 4th and 5th datasets) is downloadable at:
//   www.sanmayce.com/Quicksort_says_rev9.zip 
// - To reproduce the roster, run on Windows or Linux:
//   - BENCH_ICL32GB.BAT
//   - BENCH_ICL64GB.BAT
//   - sh bench_gcc32GB.sh
//   - sh bench_gcc64GB.sh
// - 3rd dataset is downloadable at:
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso 
// - 4th dataset is downloadable at:
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/aarch64/images/Fedora-Workstation-35-1.2.aarch64.raw.xz 
// - 5th dataset is downloadable at:
// https://download.kiwix.org/zim/stack_exchange/math.stackexchange.com_en_all_2019-02.zim


//# //https://stackoverflow.com/questions/2061245/how-to-subtract-two-unsigned-ints-with-wrap-around-or-overflow
//# /*
//# Here's a little more detail of why it 'just works' when you subtract the 'smaller' from the 'larger'.
//# 
//# A couple of things going into this…
//# 1. In hardware, subtraction uses addition: The appropriate operand is simply negated before being added.
//# 2. In two’s complement (which pretty much everything uses), an integer is negated by inverting all the bits then adding 1.
//# 
//# Hardware does this more efficiently than it sounds from the above description, but that’s the basic algorithm for subtraction (even when values are unsigned).
//# 
//# So, lets figure 2 – 250 using 8bit unsigned integers. In binary we have
//# 
//#   0 0 0 0 0 0 1 0  
//# - 1 1 1 1 1 0 1 0
//# We negate the operand being subtracted and then add. Recall that to negate we invert all the bits then add 1. After inverting the bits of the second operand we have
//# 
//# 0 0 0 0 0 1 0 1  
//# Then after adding 1 we have
//# 
//# 0 0 0 0 0 1 1 0  
//# Now we perform addition...
//# 
//#   0 0 0 0 0 0 1 0   
//# + 0 0 0 0 0 1 1 0
//# 
//# = 0 0 0 0 1 0 0 0 = 8, which is the result we wanted from 2 - 250
//# */
//# 
//# //https://stackoverflow.com/questions/7221409/is-unsigned-integer-subtraction-defined-behavior?noredirect=1
//# 
//# #include <stdint.h>
//# #include <stdio.h>
//# 
//# int main()
//# {
//# 
//# uint64_t SGNDmax = 1LL<<63;
//# uint64_t UNSGNDmax = -1;
//# //[[[
//#     uint8_t x = 0xff;
//#     uint8_t y = x + 20;
//#     int8_t res1;
//#     int8_t res2;
//# //]]]
//# 
//# //Well, an unsigned integer subtraction has defined behavior, also it is a tricky thing. 
//# //When you subtract two unsigned integers, result is promoted to higher type int if result (lvalue) type is not specified explicitly. 
//# //In the latter case, for example, int8_t result = a - b; (where a and b have int8_t type) you can obtain very weird behavior. 
//# //I mean you may loss transitivity property (i.e. if a > b and b > c it is true that a > c). 
//# //The loss of transitivity can destroy a tree-type data structure work. 
//# //Care must be taken not to provide comparison function for sorting, searching, tree building that uses unsigned integer subtraction to deduce which key is higher or lower.
//# //See example below.
//# 
//#     uint8_t a = 255;
//#     uint8_t b = 100;
//#     uint8_t c = 150;
//# 
//# //In Linux it is %llu and in Windows it is %I64u
//# printf("uint64_t SGNDmax = 1LL<<63 = %llu\n", SGNDmax);
//# printf("uint64_t UNSGNDmax = -1 = %llu\n\n", UNSGNDmax);
//# printf("uint64_t SGNDmax = 1LL<<63 = 0x%llX\n", SGNDmax);
//# printf("uint64_t UNSGNDmax = -1 = 0x%llX\n\n", UNSGNDmax);
//# 
//# //[[[
//#     printf("(uint8_t)x = %d\n", (uint8_t)x);
//#     printf("(uint8_t)y = %d\n", (uint8_t)y);
//# 
//#     printf("(int8_t)x = %d\n", (int8_t)x);
//#     printf("(int8_t)y = %d\n", (int8_t)y);
//# 
//#     res1 = (int8_t)x - y;
//#     res2 = (int8_t)y - x;
//#     printf("(int8_t)x - y = %d\n", res1);
//#     printf("(int8_t)y - x = %d\n", res2);
//# 
//#     res1 = (uint8_t)x - (uint8_t)y;
//#     res2 = (uint8_t)y - (uint8_t)x;
//#     printf("x and y: %d and %d\n", x, y);
//#     printf("(uint8_t)x - (uint8_t)y = %d\n", res1);
//#     printf("(uint8_t)y - (uint8_t)x = %d\n\n", res2);
//# //]]]
//# 
//#     printf("uint8_t a = %+d, b = %+d, c = %+d\n\n", a, b, c);
//# 
//#     printf("          b - a  = %+d\tpromotion to int type\n"
//#            " (int8_t)(b - a) = %+d\n\n"
//#            "          b + a  = %+d\tpromotion to int type\n"
//#            "(uint8_t)(b + a) = %+d\tmodular arithmetic\n"
//#            "     b + a %% %d = %+d\n\n", 
//#            b - a,  (int8_t)(b - a), 
//#            b + a, (uint8_t)(b + a),
//#            UINT8_MAX + 1,
//#            (b + a) % (UINT8_MAX + 1));
//# 
//# // Modified by Kaze:
//#     printf("b %s c (b - c = %d), b %s a (b - a = %d), AND c %s a (c - a = %d)\n",
//#            (int8_t)(b - c) < 0 ? "<" : ">", (int8_t)(b - c),
//#            (int8_t)(b - a) < 0 ? "<" : ">", (int8_t)(b - a),
//#            (int8_t)(c - a) < 0 ? "<" : ">", (int8_t)(c - a));
//#     return 0;
//# }
//# 
//# /*
//# F:\Quicksort_says_rev8++>notepad e.c
//# 
//# F:\Quicksort_says_rev8++>icl e.c
//# Intel(R) C++ Compiler XE for applications running on IA-32, Version 15.0.0.108 Build 20140726
//# Copyright (C) 1985-2014 Intel Corporation.  All rights reserved.
//# 
//# e.c
//# Microsoft (R) Incremental Linker Version 10.00.40219.01
//# Copyright (C) Microsoft Corporation.  All rights reserved.
//# 
//# -out:e.exe
//# e.obj
//# 
//# F:\Quicksort_says_rev8++>e
//# uint64_t SGNDmax = 1LL<<63 = 9223372036854775808
//# uint64_t UNSGNDmax = -1 = 18446744073709551615
//# 
//# uint64_t SGNDmax = 1LL<<63 = 0x8000000000000000
//# uint64_t UNSGNDmax = -1 = 0xFFFFFFFFFFFFFFFF
//# 
//# (uint8_t)x = 255
//# (uint8_t)y = 19
//# (int8_t)x = -1
//# (int8_t)y = 19
//# (int8_t)x - y = -20
//# (int8_t)y - x = 20
//# x and y: 255 and 19
//# (uint8_t)x - (uint8_t)y = -20
//# (uint8_t)y - (uint8_t)x = 20
//# 
//# uint8_t a = +255, b = +100, c = +150
//# 
//#           b - a  = -155 promotion to int type
//#  (int8_t)(b - a) = +101
//# 
//#           b + a  = +355 promotion to int type
//# (uint8_t)(b + a) = +99  modular arithmetic
//#      b + a % 256 = +99
//# 
//# b < c (b - c = -50), b > a (b - a = 101), AND c < a (c - a = -105)
//# 
//# F:\Quicksort_says_rev8++>
//# */


/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; mark_description "-FAcs -O3 -D_N_HIGH_PRIORITY";
; ae-64+2=76 bytes, 5/1 conditional/unconditional jumps
; 'Magnetica' partitioning, mainloop rev.4[

.B15.5::                        
  00064 49 ff c6         inc r14                                
  00067 4e 8b 14 f1      mov r10, QWORD PTR [rcx+r14*8]         
  0006b 4d 3b ea         cmp r13, r10                           
  0006e 77 2c            ja .B15.14 
.B15.6::                        
  00070 73 39            jae .B15.15 
.B15.7::                        
  00072 4e 8b 3c c1      mov r15, QWORD PTR [rcx+r8*8]          
  00076 4d 3b ef         cmp r13, r15                           
  00079 73 0c            jae .B15.11 
.B15.9::                        
  0007b 49 ff c8         dec r8                                 
  0007e 4e 8b 3c c1      mov r15, QWORD PTR [rcx+r8*8]          
  00082 4d 3b ef         cmp r13, r15                           
  00085 72 f4            jb .B15.9 
.B15.11::                       
  00087 4d 3b f0         cmp r14, r8                            
  0008a 7d 08            jge .B15.13 
.B15.12::                       
  0008c 4e 89 3c f1      mov QWORD PTR [rcx+r14*8], r15         
  00090 4e 89 14 c1      mov QWORD PTR [rcx+r8*8], r10          
.B15.13::                       
  00094 49 ff c8         dec r8                                 
  00097 49 ff ce         dec r14                                
  0009a eb 0f            jmp .B15.15 
.B15.14::                       
  0009c 4c 8b 3c e9      mov r15, QWORD PTR [rcx+rbp*8]         
  000a0 4c 89 14 e9      mov QWORD PTR [rcx+rbp*8], r10         
  000a4 48 ff c5         inc rbp                                
  000a7 4e 89 3c f1      mov QWORD PTR [rcx+r14*8], r15         
.B15.15::                       
  000ab 4d 3b f0         cmp r14, r8                            
  000ae 7c b4            jl .B15.5 
; 'Magnetica' partitioning, mainloop rev.4]
*/

    #ifdef revision4
            for (;PR < Jndx;) {
                PR = PR + 1;
                if (Pivot > QWORDS[PR]) {
                    swapUnconditional (&QWORDS[PL], &QWORDS[PR]);
                    PL = PL + 1;
                //} else if (Pivot == QWORDS[PR]) {
                } else if (Pivot < QWORDS[PR]) {
                    for (;Pivot < QWORDS[Jndx];) {
                        Jndx = Jndx - 1;
                    }
                    if (PR < Jndx) swapUnconditional (&QWORDS[PR], &QWORDS[Jndx]);
                    Jndx = Jndx - 1;
                    PR = PR - 1;
                }
            }
    #endif
/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; ae-64+2=76 bytes i.e. (94-76=18 less), 5/1 conditional/unconditional jumps i.e. 2-1=1 less unconditional jump than r.1
; 'Magnetica' partitioning, mainloop rev.2[
.B4.5::                         
  00064 48 ff c5         inc rbp                                
  00067 48 8b 14 e9      mov rdx, QWORD PTR [rcx+rbp*8]         
  0006b 4c 3b ea         cmp r13, rdx                           
  0006e 77 2c            ja .B4.14 
.B4.6::                         
  00070 73 39            jae .B4.15 
.B4.7::                         
  00072 4e 8b 3c d9      mov r15, QWORD PTR [rcx+r11*8]         
  00076 4d 3b ef         cmp r13, r15                           
  00079 73 0c            jae .B4.11 
.B4.9::                         
  0007b 49 ff cb         dec r11                                
  0007e 4e 8b 3c d9      mov r15, QWORD PTR [rcx+r11*8]         
  00082 4d 3b ef         cmp r13, r15                           
  00085 72 f4            jb .B4.9 
.B4.11::                        
  00087 49 3b eb         cmp rbp, r11                           
  0008a 7d 08            jge .B4.13 
.B4.12::                        
  0008c 4c 89 3c e9      mov QWORD PTR [rcx+rbp*8], r15         
  00090 4a 89 14 d9      mov QWORD PTR [rcx+r11*8], rdx         
.B4.13::                        
  00094 49 ff cb         dec r11                                
  00097 48 ff cd         dec rbp                                
  0009a eb 0f            jmp .B4.15 
.B4.14::                        
  0009c 4e 8b 3c f1      mov r15, QWORD PTR [rcx+r14*8]         
  000a0 4a 89 14 f1      mov QWORD PTR [rcx+r14*8], rdx         
  000a4 49 ff c6         inc r14                                
  000a7 4c 89 3c e9      mov QWORD PTR [rcx+rbp*8], r15         
.B4.15::                        
  000ab 49 3b eb         cmp rbp, r11                           
  000ae 7c b4            jl .B4.5 
; 'Magnetica' partitioning, mainloop rev.2]
*/
    #ifdef revision3
            for (;PR < Jndx;) {
                // Many thanks go to Orson Peters for sharing his Pattern-defeating quicksort (pdqsort) at GitHub.
                // This is due to a new technique described in "BlockQuicksort: How Branch Mispredictions don't affect Quicksort" by Stefan Edelkamp and Armin Weiss.
                Stefan_Edelkamp_Armin_Weiss1 = (Pivot > QWORDS[PR + 1]);
                Stefan_Edelkamp_Armin_Weiss2 = (Pivot == QWORDS[PR + 1]);
                Stefan_Edelkamp_Armin_Weiss3 = (Pivot < QWORDS[PR + 1]);
                tmp = minSO(QWORDS[PL], QWORDS[PR + 1]); QWORDS[PR + 1] = maxSO(QWORDS[PL], QWORDS[PR + 1]); QWORDS[PL] = tmp; // Since Pivot is equal to QWORDS[PL]
                PL = PL + Stefan_Edelkamp_Armin_Weiss1;
                PR = PR + Stefan_Edelkamp_Armin_Weiss1;
                PR = PR + Stefan_Edelkamp_Armin_Weiss2;
                if (Stefan_Edelkamp_Armin_Weiss3) {
                    for (;Pivot < QWORDS[Jndx];) {
                        Jndx = Jndx - 1;
                    }
                    if (PR + 1 < Jndx) swapUnconditional (&QWORDS[PR + 1], &QWORDS[Jndx]);
                    Jndx = Jndx - 1;
                }
            }
    #endif
/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; f9-73+6=140 bytes, 4/0 conditional/unconditional jumps
; 'Magnetica' partitioning, mainloop rev.3[
.B7.5::                         
  00073 4a 8b 5c f1 08   mov rbx, QWORD PTR [8+rcx+r14*8]       
  00078 33 d2            xor edx, edx                           
  0007a 4c 3b eb         cmp r13, rbx                           
  0007d 4a 8b 2c c1      mov rbp, QWORD PTR [rcx+r8*8]          
  00081 49 0f 47 d4      cmova rdx, r12                         
  00085 45 33 ff         xor r15d, r15d                         
  00088 48 3b eb         cmp rbp, rbx                           
  0008b 48 89 ee         mov rsi, rbp                           
  0008e 41 0f 92 c7      setb r15b                              
  00092 48 33 f3         xor rsi, rbx                           
  00095 41 f7 df         neg r15d                               
  00098 4d 63 ff         movsxd r15, r15d                       
  0009b 49 23 f7         and rsi, r15                           
  0009e 48 33 ee         xor rbp, rsi                           
  000a1 4c 3b eb         cmp r13, rbx                           
  000a4 4a 89 6c f1 08   mov QWORD PTR [8+rcx+r14*8], rbp       
  000a9 bd 00 00 00 00   mov ebp, 0                             
  000ae 49 0f 44 ec      cmove rbp, r12                         
  000b2 48 33 f3         xor rsi, rbx                           
  000b5 4a 89 34 c1      mov QWORD PTR [rcx+r8*8], rsi          
  000b9 4c 03 c2         add r8, rdx                            
  000bc 48 03 d5         add rdx, rbp                           
  000bf 4c 03 f2         add r14, rdx                           
  000c2 4c 3b eb         cmp r13, rbx                           
  000c5 73 2f            jae .B7.13 
.B7.6::                         
  000c7 4a 8b 14 c9      mov rdx, QWORD PTR [rcx+r9*8]          
  000cb 4c 3b ea         cmp r13, rdx                           
  000ce 73 0c            jae .B7.10 
.B7.8::                         
  000d0 49 ff c9         dec r9                                 
  000d3 4a 8b 14 c9      mov rdx, QWORD PTR [rcx+r9*8]          
  000d7 4c 3b ea         cmp r13, rdx                           
  000da 72 f4            jb .B7.8 
.B7.10::                        
  000dc 49 8d 5e 01      lea rbx, QWORD PTR [1+r14]             
  000e0 4c 3b cb         cmp r9, rbx                            
  000e3 7e 0e            jle .B7.12 
.B7.11::                        
  000e5 4a 8b 5c f1 08   mov rbx, QWORD PTR [8+rcx+r14*8]       
  000ea 4a 89 54 f1 08   mov QWORD PTR [8+rcx+r14*8], rdx       
  000ef 4a 89 1c c9      mov QWORD PTR [rcx+r9*8], rbx          
.B7.12::                        ; Preds .B7.10 .B7.11
  000f3 49 ff c9         dec r9                                 
.B7.13::                        
  000f6 4d 3b f1         cmp r14, r9                            
  000f9 0f 8c 74 ff ff 
        ff               jl .B7.5 
; 'Magnetica' partitioning, mainloop rev.3]
*/
            Jndx = PL - 1;
            Indx = PR + 1;
/*
            // 'Magnetica' partitioning [
            Jndx = Right;
            PL = Left;
            PR = Left;
            swap (&QWORDS[(Left + Right)>>1], &QWORDS[PR]);
            Pivot = QWORDS[PR];
            for (;PR < Jndx;) {
                if (Pivot > QWORDS[PR + 1]) {
                    swap (&QWORDS[PL], &QWORDS[PR + 1]);
                    PL = PL + 1;
                    PR = PR + 1;
                } else if (Pivot == QWORDS[PR + 1]) {
                    PR = PR + 1;
                } else {
                    for (;Pivot < QWORDS[Jndx];) {
                        Jndx = Jndx - 1;
                    }
                    if (PR + 1 < Jndx) swap (&QWORDS[PR + 1], &QWORDS[Jndx]);
                    Jndx = Jndx - 1;
                }
            }
            Jndx = PL - 1;
            Indx = PR + 1;
            // 'Magnetica' partitioning ]
*/
/*
; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
; c6-6a+2=94 bytes, 5/2 conditional/unconditional jumps
; 'Magnetica' partitioning, mainloop [
.B4.5::                         
  0006a 4e 3b 5c e9 08   cmp r11, QWORD PTR [8+rcx+r13*8]       
  0006f 77 37            ja .B4.15 
.B4.6::                         
  00071 75 08            jne .B4.8 
.B4.7::                         
  00073 49 89 d5         mov r13, rdx                           
  00076 48 ff c2         inc rdx                                
  00079 eb 48            jmp .B4.16 
.B4.8::                         
  0007b 4e 8b 34 c1      mov r14, QWORD PTR [rcx+r8*8]          
  0007f 4d 3b de         cmp r11, r14                           
  00082 73 0c            jae .B4.12 
.B4.10::                        
  00084 49 ff c8         dec r8                                 
  00087 4e 8b 34 c1      mov r14, QWORD PTR [rcx+r8*8]          
  0008b 4d 3b de         cmp r11, r14                           
  0008e 72 f4            jb .B4.10 
.B4.12::                        
  00090 4c 3b c2         cmp r8, rdx                            
  00093 7e 0e            jle .B4.14 
.B4.13::                        
  00095 4e 8b 7c e9 08   mov r15, QWORD PTR [8+rcx+r13*8]       
  0009a 4e 89 74 e9 08   mov QWORD PTR [8+rcx+r13*8], r14       
  0009f 4e 89 3c c1      mov QWORD PTR [rcx+r8*8], r15          
.B4.14::                        
  000a3 49 ff c8         dec r8                                 
  000a6 eb 1b            jmp .B4.16 
.B4.15::                        
  000a8 4e 8b 74 e9 08   mov r14, QWORD PTR [8+rcx+r13*8]       
  000ad 4e 8b 3c e1      mov r15, QWORD PTR [rcx+r12*8]         
  000b1 4e 89 34 e1      mov QWORD PTR [rcx+r12*8], r14         
  000b5 49 ff c4         inc r12                                
  000b8 4e 89 7c e9 08   mov QWORD PTR [8+rcx+r13*8], r15       
  000bd 49 89 d5         mov r13, rdx                           
  000c0 48 ff c2         inc rdx                                
.B4.16::                        
  000c3 4d 3b e8         cmp r13, r8                            
  000c6 7c a2            jl .B4.5 
; 'Magnetica' partitioning, mainloop ]
*/
    #ifdef FinishWithInsertionSort
            GearBox = ( maxSO((Right-Indx), (Jndx-Left)) > minSO((Right-Indx), (Jndx-Left))<<6 ); // same as MAX/MIN > 64, i.e. Gear=1 if we need Median of 7
    #endif
            if (Indx + InsertionsortTHRESHOLD < Right) { // still refusing to go (always) with the smaller partition first...
                StackPtr = StackPtr + 2;
                Stack[StackPtr - 1] = Indx;
                Stack[StackPtr] = Right;
    #ifdef FinishWithInsertionSort
                // Stack is full, bail out and finalize with Insertionsort [
                StackPtr = StackPtr*(StackPtr + 2 <= StackEntries-1);  // StackPtr should be enforced FALSE; also, ensure the next 'push' above is sanctioned - the max index of Stack[] being 'StackEntries-1'
                Right = Right*(StackPtr + 2 <= StackEntries-1); // Left + InsertionsortTHRESHOLD < Right should be enforced FALSE:
                // Stack is full, bail out and finalize with Insertionsort ]
    #endif
            }
            Right = Jndx;
        } //while (Left + InsertionsortTHRESHOLD < Right);
    } while ( (StackPtr != 0) );
    #ifdef FinishWithInsertionSort
    for (Indx=LeftBackup+1; Indx <= RightBackup; Indx++) {
        Jndx = Indx;
        for (;Jndx >= 1;) {
            if (QWORDS[Jndx-1] > QWORDS[Jndx]) swapUnconditional (&QWORDS[Jndx-1], &QWORDS[Jndx]); else break;
            Jndx = Jndx - 1;
        }
    }
    #endif
}
// My threads with Magnetica's source and binaries (Linux and Windows):
// https://www.overclock.net/threads/benchmark-quicksort-says-sorting-2-billion-qwords.1794855/
// https://www.qb64.org/forum/index.php?topic=3518.msg137645#msg137645
// https://www.linuxquestions.org/questions/programming-9/qsort-vs-%27magnetica%27-quicksort-4175703333/#post6299782
// Quicksort 'Magnetica' r.6, unbreakable (never overflowing the stack) when '#define FinishWithInsertionSort' is uncommented ]


/*
void scalar_partition_epi32(uint32_t* array, const uint32_t pivot, int& left, int& right) {
    while (left <= right) {
        while (array[left] < pivot) {
            left += 1;
        }
        while (array[right] > pivot) {
            right -= 1;
        }
        if (left <= right) {
            const uint32_t t = array[left];
            array[left]      = array[right];
            array[right]     = t;
            left  += 1;
            right -= 1;
        }
    }
}

int lomuto_partition_epi32(uint32_t* array, int lo, int hi) {
    const uint32_t pivot = array[(lo + hi)/2];
    const uint32_t hi_value = array[hi];
    array[(lo + hi)/2] = hi_value;
    array[hi] = pivot;
    int i = lo;

    for (int j=lo; j < hi; j++) {
        if (array[j] <= pivot) {
            const uint32_t t = array[i];
            array[i] = array[j];
            array[j] = t;
            i += 1;
        }
    }
    {
        const uint32_t t = array[i];
        array[i]  = array[hi];
        array[hi] = t;
        i += 1;
    }
    return i;
}
*/





// https://stackoverflow.com/questions/2786899/fastest-sort-of-fixed-length-6-int-array

//    //#define SWAP(x,y) asm("mov %0, %2 ; cmp %1, %0 ; cmovg %1, %0 ; cmovg %2, %1" : "=r" (x), "=r" (y), "=r" (tmp) : "0" (x), "1" (y) : "cc");
//    #define SWAP(x,y) { int dx = d[x]; int dy = d[y]; int tmp = d[x] = dx < dy ? dx : dy; d[y] ^= dx ^ tmp; }

/*
    static inline void sort6_sorting_network_v4(int * d){
    #define min(x, y) (y ^ ((x ^ y) & -(x < y)))
    #define max(x, y) (x ^ ((x ^ y) & -(x < y)))
    #define SWAP(x,y) { int tmp = min(d[x], d[y]); d[y] = max(d[x], d[y]); d[x] = tmp; }
        SWAP(1, 2);
        SWAP(4, 5);
        SWAP(0, 2);
        SWAP(3, 5);
        SWAP(0, 1);
        SWAP(3, 4);
        SWAP(1, 4);
        SWAP(0, 3);
        SWAP(2, 5);
        SWAP(1, 3);
        SWAP(2, 4);
        SWAP(2, 3);
    #undef SWAP
    #undef min
    #undef max
    }
*/

/*
    static inline void sort6_rank_order_reg(int *d) {
        register int x0,x1,x2,x3,x4,x5;
        x0 = d[0];
        x1 = d[1];
        x2 = d[2];
        x3 = d[3];
        x4 = d[4];
        x5 = d[5];
        int o0 = (x0>x1)+(x0>x2)+(x0>x3)+(x0>x4)+(x0>x5);
        int o1 = (x1>=x0)+(x1>x2)+(x1>x3)+(x1>x4)+(x1>x5);
        int o2 = (x2>=x0)+(x2>=x1)+(x2>x3)+(x2>x4)+(x2>x5);
        int o3 = (x3>=x0)+(x3>=x1)+(x3>=x2)+(x3>x4)+(x3>x5);
        int o4 = (x4>=x0)+(x4>=x1)+(x4>=x2)+(x4>=x3)+(x4>x5);
        int o5 = 15-(o0+o1+o2+o3+o4);
        d[o0]=x0; d[o1]=x1; d[o2]=x2; d[o3]=x3; d[o4]=x4; d[o5]=x5;
    }
*/

/*
    static inline void sort6_inlined_bubble(int * d){
    #define SWAP(x,y) { int dx = d[x], dy = d[y], tmp; tmp = d[x] = dx < dy ? dx : dy; d[y] ^= dx ^ tmp; }
        SWAP(0,1); SWAP(1,2); SWAP(2,3); SWAP(3,4); SWAP(4,5);
        SWAP(0,1); SWAP(1,2); SWAP(2,3); SWAP(3,4);
        SWAP(0,1); SWAP(1,2); SWAP(2,3);
        SWAP(0,1); SWAP(1,2);
        SWAP(0,1);
    #undef SWAP
    }
*/

// Sandy Bridge (i7-2600k)
// =======================
// Direct call to qsort library function      559.97   451.88   464.84   491.35   458.11
// Naive implementation (insertion sort)      341.15   160.26   160.45   154.40   106.54
// Insertion Sort (Daniel Stutzbach)          284.17   136.74   132.69   123.85   121.77
// Insertion Sort Unrolled                    239.40   110.49   114.81   110.79   117.30
// Rank Order                                 114.24   76.42    45.31    36.96    36.73
// Rank Order with registers                  105.09   32.31    48.54    32.51    33.29
// Sorting Networks (Daniel Stutzbach)        210.56   115.68   116.69   107.05   124.08
// Sorting Networks (Paul R)                  364.03   66.02    61.64    45.70    44.19
// Sorting Networks 12 with Fast Swap         246.97   41.36    59.03    41.66    38.98
// Sorting Networks 12 reordered Swap         235.39   38.84    47.36    38.61    37.29
// Reordered Sorting Network w/ fast swap     115.58   27.23    27.75    27.25    26.54



void printArray(uint64_t array[], int64_t size) {
int64_t i;
for (i = 0; i < size; ++i) printf("%016llX\n", array[i]);
}

int cmpfunc (const void * a, const void * b) {
	if ( *(uint64_t*)a > *(uint64_t*)b ) return 1;
	else if ( *(uint64_t*)a < *(uint64_t*)b ) return -1;
	//else ( *(uint64_t*)a = *(uint64_t*)b ) return 0;
	return 0;
}

// taken from bench.c by Scandum in order to have the same comparer:
int cmp_8(const void * a, const void * b)
{
	//return *(uint64_t *)a > *(uint64_t *)b ? 1 : 0;
	return (*(uint64_t*)a > *(uint64_t*)b) - (*(uint64_t*)a < *(uint64_t*)b);
}


int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;
g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}

#include <time.h>
#include <string.h> // gcc complains for strcmp

#include "quadsort.h"
//#include "fluxsort.h"
#include "crumsort.h"
//#include "Magnetica_v12.h"
//#include "Magnetica_v13.h"
#include "Magnetica_v14.h"
#include "Magnetica_v15.h"
#include "Magnetica_v16.h"
#include "Akkodah_v1.h"

#ifdef _N_HIGH_PRIORITY
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686219.aspx
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#endif

#ifdef _N_HIGH_PRIORITY_GCC
//#include <sys/time.h>
#include <sys/resource.h>
//int main(){
//    setpriority(PRIO_PROCESS, 0, -20);
//}
//Note that you must be running as superuser for this to work. (for more info, type 'man setpriority' at a prompt.)
#endif

int main(int argc, char **argv)
{
	uint64_t data[] = {8, 7, 2, 1, 0, 9, 6, 15};
	uint64_t QWORDS[] = {8, 7, 2, 1, 0, 9, 6};
  	int64_t n = sizeof(data) / sizeof(data[0]);
time_t time1,time2;

//FILE *fp_outLINE;
FILE *fp_outLINE2;
FILE *fp_outLINE3;
uint64_t digit[1];
uint64_t elements;
uint64_t counter;
uint64_t *FabriceBellard_DIGITS;
uint64_t *xgamsCACHE;
char *AvoidSEEKS;
int64_t i,j;
uint64_t UniqueElements = 1, Previous;
int ditto;

#ifdef _N_HIGH_PRIORITY
   DWORD dwError, dwPriClass;
#endif

uint64_t MicroPartition;

/*
i=10;
j=300;
MicroPartition=j-i;

MicroPartition=8192;
MicroPartition = (1*!!((MicroPartition)>>13)) + (1*!!((MicroPartition)>>9)); // 8192[+] 512[+] 13..511
		printf("%d",MicroPartition);

MicroPartition=512;
MicroPartition = (1*!!((MicroPartition)>>13)) + (1*!!((MicroPartition)>>9)); // 8192[+] 512[+] 13..511
		printf("%d",MicroPartition);

MicroPartition=511;
MicroPartition = (1*!!((MicroPartition)>>13)) + (1*!!((MicroPartition)>>9)); // 8192[+] 512[+] 13..511
		printf("%d",MicroPartition);

// MicroPartition=2 for 8192[+]
// MicroPartition=1 for 512[+]
// MicroPartition=0 for 511[-]
*/

//MicroPartition=14*(MicroPartition>(1LL<<13));
//switch (MicroPartition) {
//	case 14:
//		printf("14");
//	case 13:
//		printf("13");
//		break;
//	case 0:
//		printf("Mid-MId; Mid; 3rd");
//	default:
//		printf("def");		
//}
//exit(1);

/*
    register uint64_t x0,x1,x2,x3,x4,x5,x6;
    int o0,o1,o2,o3,o4,o5,o6;
    int TheMiddleOfMiddle=0;
	printf("Unsorted Array:\n");
	printArray(QWORDS, 7);
  
            x0 = QWORDS[TheMiddleOfMiddle+0];
            x1 = QWORDS[TheMiddleOfMiddle+1];
            x2 = QWORDS[TheMiddleOfMiddle+2];
            x3 = QWORDS[TheMiddleOfMiddle+3];
            x4 = QWORDS[TheMiddleOfMiddle+4];
            x5 = QWORDS[TheMiddleOfMiddle+5];
            x6 = QWORDS[TheMiddleOfMiddle+6];
            o0 = (x0>x1)+(x0>x2)+(x0>x3)+(x0>x4)+(x0>x5)+(x0>x6);
            o1 = (x1>=x0)+(x1>x2)+(x1>x3)+(x1>x4)+(x1>x5)+(x1>x6);
            o2 = (x2>=x0)+(x2>=x1)+(x2>x3)+(x2>x4)+(x2>x5)+(x2>x6);
            o3 = (x3>=x0)+(x3>=x1)+(x3>=x2)+(x3>x4)+(x3>x5)+(x3>x6);
            o4 = (x4>=x0)+(x4>=x1)+(x4>=x2)+(x4>=x3)+(x4>x5)+(x4>x6);
            o5 = (x5>=x0)+(x5>=x1)+(x5>=x2)+(x5>=x3)+(x5>=x4)+(x5>x6);
            o6 = (0+1+2+3+4+5+6)-(o0+o1+o2+o3+o4+o5);
            QWORDS[TheMiddleOfMiddle+o0]=x0; QWORDS[TheMiddleOfMiddle+o1]=x1; QWORDS[TheMiddleOfMiddle+o2]=x2; QWORDS[TheMiddleOfMiddle+o3]=x3; QWORDS[TheMiddleOfMiddle+o4]=x4; QWORDS[TheMiddleOfMiddle+o5]=x5; QWORDS[TheMiddleOfMiddle+o6]=x6;
  
  
	printf("Sorted array in ascending order: \n");
	printArray(QWORDS, 7);
	exit(0);
*/

#ifdef _N_HIGH_PRIORITY_GCC
setpriority(PRIO_PROCESS, 0, -20);

// setpriority(3) - Linux man page
// #include <sys/resource.h>
// int getpriority(int which, id_t who);
// int setpriority(int which, id_t who, int value); 
// The getpriority() function shall obtain the nice value of a process, process group, or user. The setpriority() function shall set the nice value of a process, process group, or user to value+ {NZERO}.
// Target processes are specified by the values of the which and who arguments. The which argument may be one of the following values: PRIO_PROCESS, PRIO_PGRP, or PRIO_USER, indicating that the who argument is to be interpreted as a process ID, a process group ID, or an effective user ID, respectively. A 0 value for the who argument specifies the current process, process group, or user.
//int which = PRIO_PROCESS;
//id_t pid;
//int ret;
//pid = getpid();
//ret = getpriority(which, pid);

printf("Current priority is %d.\n",getpriority(PRIO_PROCESS, 0));
#endif

#ifdef _N_HIGH_PRIORITY
   if(!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
   {
//      _tprintf(TEXT("Already REALTIME_PRIORITY.\n"));
//      goto Cleanup;
   } 
   if(!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
   {
//      _tprintf(TEXT("Already REALTIME_PRIORITY.\n"));
//      goto Cleanup;
   } 
   // Display priority class

   dwPriClass = GetPriorityClass(GetCurrentProcess());

   //_tprintf(TEXT("Current priority class is 0x%x\n"), dwPriClass);

//if (argc == 2) {} else // 2020-Jan-13
   if (dwPriClass==0x00000080) printf("Current priority class is HIGH_PRIORITY_CLASS.\n");
//if (argc == 2) {} else // 2020-Jan-13
   if (dwPriClass==0x00000100) printf("Current priority class is REALTIME_PRIORITY_CLASS.\n");
#endif

#ifdef _N_HIGH_PRIORITY
// https://habrahabr.ru/post/113682/
// Andrew Aksyonoff [

//SetProcessAffinityMask(GetCurrentProcess(), 1); // 2020-Dec-09, causes problems in real-time priority with newer Windows 10

	//volatile int zomg = 1;
	//for ( int i=1; i<1000000000; i++ )
	//	zomg *= i;
// Andrew Aksyonoff ]
#endif

/*
	printf("Unsorted Array:\n");
	printArray(data, n);
  
  	QuickSortHoare(data, 0, n - 1);
  
	printf("Sorted array in ascending order: \n");
	printArray(data, n);
	exit(0);
*/

//srand(time(0));
//while (1){
//int64_t RandIndex;
	//RandIndex = rand()%(10 - 0) + 0; //0..9
	//RandIndex = rand()%(10 - 2) + 2; //2..9
	//RandIndex = rand()%(11 - 2) + 2; //2..10
	//RandIndex = rand()%(11 - 10) + 10; //10
	//RandIndex = rand()%(2 - 0); // 0..1
	//printf( "%lu\n", RandIndex );
//}

// Too lazy to get the size... 24823016

goto SkipGene;
	printf("Generating the dataset ... ");	
	while(e/=2){
	N*=2;U=U*1LL*(m+1)/2%m;
	for(s=N;s/=2;)g(136,0);
	for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;
	for(s=1;s<N;s*=2)g(839354248,1);
	for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a%10,a/=10;
	}
	printf("Done.\n");	
	while(!*--p);
	//for(t[0]--;p>=t;)putchar(48+*p--);

//if( ( fp_outLINE = fopen( "Fabrice_at-each-position.txt", "wb" ) ) == NULL )
//{ printf( "Can't open 'Fabrice_at-each-position.txt' file.\n" ); return( 1 ); }
// 178,708,944/8=22,338,618
elements = 22338618LL;
printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8 );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "22338618_QWORDS.bin", "wb" ) ) == NULL )
{ printf( "Can't open '22338618_QWORDS.bin' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "22338618_QWORDS.bin.sorted", "wb" ) ) == NULL )
{ printf( "Can't open '22338618_QWORDS.bin.sorted' file.\n" ); return( 1 ); }
counter=0;
	for(t[0]--;p>=t;) {
		digit[0]=(48+*p--);
		//fprintf( fp_outLINE, "%c", (48+*p--));
		fwrite( &digit[0], 8, 1, fp_outLINE2 );
		xgamsCACHE[counter]=digit[0];
		counter++;
	}
fflush(fp_outLINE2);

SkipGene:

if (argc==3) {

	if (strcmp(argv[2],"many")==0) {
ditto = 100;
// "mobythesaurus.txt" is 24823016, we need the lof("mobythesaurus.txt")-8+1 QWORDS
elements = 24823016LL-8+1; // BuildingBlocks are size-order+1

printf( "Allocating FILE-Buffer %luMB ...\n", ((elements -(-8+1))>>20) );
AvoidSEEKS = (char *)malloc( elements -(-8+1) );
if( AvoidSEEKS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating AUX-Buffer %luMB ...\n", ((elements*8)>>20) );
FabriceBellard_DIGITS = (uint64_t *)malloc( elements*8);
if( FabriceBellard_DIGITS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8*ditto)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8*ditto );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "mobythesaurus.txt", "rb" ) ) == NULL )
{ printf( "Can't open 'mobythesaurus.txt' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "mobythesaurus.txt.sorted", "wb" ) ) == NULL )
{ printf( "Can't open 'mobythesaurus.txt.sorted' file.\n" ); return( 1 ); }

fread( AvoidSEEKS, elements -(-8+1), 1, fp_outLINE2 );

for(j=0;j<=elements-1;j++) {
	FabriceBellard_DIGITS[j] = *(uint64_t *)(AvoidSEEKS+j);
}
	for(i=1;i<=ditto;i++) {
		for(j=0;j<=elements-1;j++) {
			xgamsCACHE[elements * (i - 1) + j] = FabriceBellard_DIGITS[j];
		}
	}
	//printf("Sorting in single-thread %lld elements...\n", elements*ditto);	

	} //if (strcmp(argv[2],"many")==0) {


	if (strcmp(argv[2],"few")==0) {
ditto = 100;
elements = 22338618LL;
printf( "Allocating AUX-Buffer %luMB ...\n", ((elements)>>20) );
FabriceBellard_DIGITS = (uint64_t *)malloc( elements*8);
if( FabriceBellard_DIGITS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8*ditto)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8*ditto );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "22338618_QWORDS.bin", "rb" ) ) == NULL )
{ printf( "Can't open '22338618_QWORDS.bin' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "22338618_QWORDS.bin.sorted", "wb" ) ) == NULL )
{ printf( "Can't open '22338618_QWORDS.bin.sorted' file.\n" ); return( 1 ); }

fread( FabriceBellard_DIGITS, elements*8, 1, fp_outLINE2 );
	for(i=1;i<=ditto;i++) {
		for(j=0;j<=elements-1;j++) {
			xgamsCACHE[elements * (i - 1) + j] = FabriceBellard_DIGITS[j];
		}
	}
	//printf("Sorting in single-thread %lld elements...\n", elements*ditto);	

	} //if (strcmp(argv[2],"few")==0) {


	if (strcmp(argv[2],"ALL")==0) {
ditto = 1;
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso
// "Fedora-Workstation-Live-x86_64-35-1.2.iso" is 24823016, we need the lof("mobythesaurus.txt")-8+1 QWORDS
elements = 2009333760LL -8+1; // BuildingBlocks are size-order+1

printf( "Allocating FILE-Buffer %luMB ...\n", ((elements -(-8+1))>>20) );
AvoidSEEKS = (char *)malloc( elements -(-8+1) );
if( AvoidSEEKS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating AUX-Buffer %luMB ...\n", ((elements*8)>>20) );
FabriceBellard_DIGITS = (uint64_t *)malloc( elements*8);
if( FabriceBellard_DIGITS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8*ditto)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8*ditto );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "Fedora-Workstation-Live-x86_64-35-1.2.iso", "rb" ) ) == NULL )
{ printf( "Can't open 'Fedora-Workstation-Live-x86_64-35-1.2.iso' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "Fedora-Workstation-Live-x86_64-35-1.2.iso.sorted", "wb" ) ) == NULL )
{ printf( "Can't open 'Fedora-Workstation-Live-x86_64-35-1.2.iso.sorted' file.\n" ); return( 1 ); }

fread( AvoidSEEKS, elements -(-8+1), 1, fp_outLINE2 );

for(j=0;j<=elements-1;j++) {
	FabriceBellard_DIGITS[j] = *(uint64_t *)(AvoidSEEKS+j);
}
	for(i=1;i<=ditto;i++) {
		for(j=0;j<=elements-1;j++) {
			xgamsCACHE[elements * (i - 1) + j] = FabriceBellard_DIGITS[j];
		}
	}
	//printf("Sorting in single-thread %lld elements...\n", elements*ditto);	

	} //if (strcmp(argv[2],"ALL")==0) {



// https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.25.tar.xz
// 1.05 GB (1,137,582,080 bytes)

	if (strcmp(argv[2],"manyC")==0) {
ditto = 1;
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso
// "Fedora-Workstation-Live-x86_64-35-1.2.iso" is 24823016, we need the lof("mobythesaurus.txt")-8+1 QWORDS
elements = 1137582080LL-8+1; // BuildingBlocks are size-order+1

printf( "Allocating FILE-Buffer %luMB ...\n", ((elements -(-8+1))>>20) );
AvoidSEEKS = (char *)malloc( elements -(-8+1) );
if( AvoidSEEKS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

//printf( "Allocating AUX-Buffer %luMB ...\n", ((elements*8)>>20) );
//FabriceBellard_DIGITS = (uint64_t *)malloc( elements*8);
//if( FabriceBellard_DIGITS == NULL )
//{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8*ditto)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8*ditto );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "linux-5.15.25.tar", "rb" ) ) == NULL )
{ printf( "Can't open 'linux-5.15.25.tar' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "linux-5.15.25.tar.sorted", "wb" ) ) == NULL )
{ printf( "Can't open 'linux-5.15.25.tar.sorted' file.\n" ); return( 1 ); }

fread( AvoidSEEKS, elements -(-8+1), 1, fp_outLINE2 );

for(j=0;j<=elements-1;j++) {
	xgamsCACHE[j] = *(uint64_t *)(AvoidSEEKS+j);
}
free(AvoidSEEKS);
	//printf("Sorting in single-thread %lld elements...\n", elements*ditto);	

	} //if (strcmp(argv[2],"manyC")==0) {


// https://download.kiwix.org/zim/stack_exchange/math.stackexchange.com_en_all_2019-02.zim
// 7.26 GB (7,798,235,442 bytes)

	if (strcmp(argv[2],"ALLmax")==0) {
ditto = 1;
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso
// "Fedora-Workstation-Live-x86_64-35-1.2.iso" is 24823016, we need the lof("mobythesaurus.txt")-8+1 QWORDS
elements = 7798235442LL -8+1; // BuildingBlocks are size-order+1

printf( "Allocating FILE-Buffer %luMB ...\n", ((elements -(-8+1))>>20) );
AvoidSEEKS = (char *)malloc( elements -(-8+1) );
if( AvoidSEEKS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

//printf( "Allocating AUX-Buffer %luMB ...\n", ((elements*8)>>20) );
//FabriceBellard_DIGITS = (uint64_t *)malloc( elements*8);
//if( FabriceBellard_DIGITS == NULL )
//{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8*ditto)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8*ditto );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "math.stackexchange.com_en_all_2019-02.zim", "rb" ) ) == NULL )
{ printf( "Can't open 'math.stackexchange.com_en_all_2019-02.zim' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "math.stackexchange.com_en_all_2019-02.zim.sorted", "wb" ) ) == NULL )
{ printf( "Can't open 'math.stackexchange.com_en_all_2019-02.zim.sorted' file.\n" ); return( 1 ); }

fread( AvoidSEEKS, elements -(-8+1), 1, fp_outLINE2 );

for(j=0;j<=elements-1;j++) {
	xgamsCACHE[j] = *(uint64_t *)(AvoidSEEKS+j);
}
free(AvoidSEEKS);
	//printf("Sorting in single-thread %lld elements...\n", elements*ditto);	

	} //if (strcmp(argv[2],"ALLmax")==0) {


// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/aarch64/images/Fedora-Workstation-35-1.2.aarch64.raw.xz
// 3.54 GB (3,803,483,832 bytes)

	if (strcmp(argv[2],"ALLmore")==0) {
ditto = 1;
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso
// "Fedora-Workstation-Live-x86_64-35-1.2.iso" is 24823016, we need the lof("mobythesaurus.txt")-8+1 QWORDS
elements = 3803483832LL -8+1; // BuildingBlocks are size-order+1

printf( "Allocating FILE-Buffer %luMB ...\n", ((elements -(-8+1))>>20) );
AvoidSEEKS = (char *)malloc( elements -(-8+1) );
if( AvoidSEEKS == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

//printf( "Allocating AUX-Buffer %luMB ...\n", ((elements*8)>>20) );
//FabriceBellard_DIGITS = (uint64_t *)malloc( elements*8);
//if( FabriceBellard_DIGITS == NULL )
//{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

printf( "Allocating Master-Buffer %luMB ...\n", ((elements*8*ditto)>>20) );
xgamsCACHE = (uint64_t *)malloc( elements*8*ditto );
if( xgamsCACHE == NULL )
{ puts( "Needed memory allocation denied!\n" ); return( 1 ); }

if( ( fp_outLINE2 = fopen( "Fedora-Workstation-35-1.2.aarch64.raw.xz", "rb" ) ) == NULL )
{ printf( "Can't open 'Fedora-Workstation-35-1.2.aarch64.raw.xz' file.\n" ); return( 1 ); }
if( ( fp_outLINE3 = fopen( "Fedora-Workstation-35-1.2.aarch64.raw.xz.sorted", "wb" ) ) == NULL )
{ printf( "Can't open 'Fedora-Workstation-35-1.2.aarch64.raw.xz.sorted' file.\n" ); return( 1 ); }

fread( AvoidSEEKS, elements -(-8+1), 1, fp_outLINE2 );

for(j=0;j<=elements-1;j++) {
	xgamsCACHE[j] = *(uint64_t *)(AvoidSEEKS+j);
}
free(AvoidSEEKS);
	//printf("Sorting in single-thread %lld elements...\n", elements*ditto);	

	} //if (strcmp(argv[2],"ALLmore")==0) {

#ifdef Commence_OpenMP
	//if ( (strcmp(argv[1],"Akkoda")==0) || (strcmp(argv[1],"BM")==0) ) {
	if ( (strcmp(argv[1],"Akkoda")==0) ) {
	printf("omp_get_num_procs( ) = %d\n", omp_get_num_procs( ));
	printf("omp_get_max_threads( ) = %d\n", omp_get_max_threads( ));
	printf("Sorting in multi-thread %lld elements...\n", elements*ditto);	
	} else printf("Sorting in single-thread %lld elements...\n", elements*ditto);	
#else
	printf("Sorting in single-thread %lld elements...\n", elements*ditto);	
#endif


// 2021-Nov-10 fix: Ugh, forgot to duplicate ditto times...

		time1=time(NULL); //fix of bigtime
		while (time1==time(NULL));
		time1=time(NULL); //fix of bigtime
//	if (strcmp(argv[1],"qsort")==0) qsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmpfunc); //r.9
	if (strcmp(argv[1],"qsort")==0) qsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmp_8); //r.9+ For some reason cmp_8 doesn't work?!
	if (strcmp(argv[1],"Magnetica10")==0) Quicksort_QB64_v10(xgamsCACHE, 0, elements*ditto - 1);  
//	if (strcmp(argv[1],"Magnetica12")==0) Quicksort_QB64_v12(xgamsCACHE, 0, elements*ditto - 1);  
	if (strcmp(argv[1],"Magnetica14")==0) Quicksort_QB64_v14(xgamsCACHE, elements*ditto);  
	if (strcmp(argv[1],"Magnetica")==0) Quicksort_QB64_v15(xgamsCACHE, elements*ditto);  
	if (strcmp(argv[1],"Akkoda")==0) QuickSortAkkoda(&xgamsCACHE[0], &xgamsCACHE[elements*ditto - 1]);  

	if (strcmp(argv[1],"Hoare")==0) QuickSortHoare(xgamsCACHE, 0, elements*ditto - 1);  
	if (strcmp(argv[1],"BM")==0) quicksort_Bentley_McIlroy_3way_partitioning(xgamsCACHE, 0, elements*ditto - 1);  
	//if (strcmp(argv[1],"FS")==0) fluxsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmp_8); //r.9+
	if (strcmp(argv[1],"CS")==0) crumsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmp_8); //r.11
		printf("Done in %d seconds.\n", (int)(time(NULL) - time1));

	printf("Sorting sorted elements...\n");	
		time1=time(NULL); //fix of bigtime
		while (time1==time(NULL));
		time1=time(NULL); //fix of bigtime
//	if (strcmp(argv[1],"qsort")==0) qsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmpfunc); //r.9
	if (strcmp(argv[1],"qsort")==0) qsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmp_8); //r.9+ For some reason cmp_8 doesn't work?!
	if (strcmp(argv[1],"Magnetica10")==0) Quicksort_QB64_v10(xgamsCACHE, 0, elements*ditto - 1);  
//	if (strcmp(argv[1],"Magnetica12")==0) Quicksort_QB64_v12(xgamsCACHE, 0, elements*ditto - 1);  
	if (strcmp(argv[1],"Magnetica14")==0) Quicksort_QB64_v14(xgamsCACHE, elements*ditto);  
	if (strcmp(argv[1],"Magnetica")==0) Quicksort_QB64_v15(xgamsCACHE, elements*ditto);  
	if (strcmp(argv[1],"Akkoda")==0) QuickSortAkkoda(&xgamsCACHE[0], &xgamsCACHE[elements*ditto - 1]);  

	if (strcmp(argv[1],"Hoare")==0) QuickSortHoare(xgamsCACHE, 0, elements*ditto - 1);  
	if (strcmp(argv[1],"BM")==0) quicksort_Bentley_McIlroy_3way_partitioning(xgamsCACHE, 0, elements*ditto - 1);  
	//if (strcmp(argv[1],"FS")==0) fluxsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmp_8); //r.9+
	if (strcmp(argv[1],"CS")==0) crumsort(xgamsCACHE, elements*ditto, sizeof(uint64_t), cmp_8); //r.11

		printf("Done in %d seconds.\n", (int)(time(NULL) - time1));

   	//QuickSortHoare(xgamsCACHE, 0, elements*ditto - 1);  
	printf("Checking whether sort went correct... ");	
	Previous = xgamsCACHE[0];
	for(counter=0;counter<elements*ditto-1;counter++) {
		if (xgamsCACHE[counter]>xgamsCACHE[counter+1]) {printf("NOT OK!\n");exit(13);};
		if (Previous != xgamsCACHE[counter]) {UniqueElements++; Previous = xgamsCACHE[counter];};
	}
	printf("OK. Unique keys = %lld\n", UniqueElements);	
	//fwrite( xgamsCACHE, elements*8, 1, fp_outLINE3 );
} //if (argc==3) {
	exit(0);
}



// https://bellard.org/mersenne.html
// A small C program to print the biggest prime number
// Here it is (448 bytes):
/*
int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<
25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]
=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}main(){while(e/=2){N*=2
;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;
for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a%10,a/=10;
}while(!*--p);for(t[0]--;p>=t;)putchar(48+*p--);}
*/
// This program computes 2^74207281-1, which was the biggest known prime number in 2016 (about 23 million digits !). For more information about how it was // found and who found it, look at the GIMPS Project .
// 
// I compiled it successfully with gcc with Linux. In order to compile it, your C compiler must support the 64 bit long long type.
// 
// In order to have a small and yet asymptotically efficient code, I decided to do the computation of 2N-1 directly in base 10. The power involves repeated // squarings and multiplications by two. The squarings are implemented by doing fast convolutions using a Number Theoretic Transform.
// 
// A previous version of this program to compute 2^6972593-1 won the International Obfuscated C Code Contest of Year 2000.
// 
// Thanks to Marco Cecchi who suggested some syntactic changes to save a few characters.
// 
// This program is Freeware.
// 
// Fabrice Bellard - http://bellard.org/ 
// last update: Sep 26, 2016
