USA, Texas, Austin, Continental Club
Dimanche 5 janvier 1987
«Merci pour l'invitation, M. Lomuto. Je rentre bientÎt en Angleterre, donc c'était juste à temps.
«Merci d'avoir acceptĂ© de me rencontrer, monsieur⊠monsieur⊠Charles⊠Anthony Richard⊠Hoare. C'est un grand honneur pour moi. Je ne sais mĂȘme pas comment vous contacter. Avez-vous un titre de chevalier?
«Appelle-moi Tony, et si tu veux, je t'appellerai Niko.
Ă premiĂšre vue, c'est un spectacle courant: deux personnes apprĂ©cient le whisky. Cependant, des dĂ©tails intrigants sont rĂ©vĂ©lĂ©s Ă l'observateur attentif. Tout d'abord - tension qui pourrait ĂȘtre coupĂ©e avec un couteau.
VĂȘtu d'un costume trois piĂšces impeccablement taillĂ© avec la dĂ©sinvolture dĂ©libĂ©rĂ©e d'un Anglais, Tony Hoare Ă©tait autant de la Grande-Bretagne qu'une tasse de thĂ©. L'expression humble sur son visage avec laquelle il sirotait de son verre, sans aucun mot, exprimait son opinion dans la dispute entre le bourbon et le scotch. Assis en face de Niko Lomuto reprĂ©sentait le contraire de lui: un programmeur vĂȘtu de jeans, mĂ©langeant whisky et cola (ce qui Ă©tait si scandaleux pour Tony qu'il a immĂ©diatement dĂ©cidĂ© de l'ignorer catĂ©goriquement - comme une odeur piquante de sueur ou un tatouage insultant), dans un Ă©tat d'une sorte de crainte dĂ©tendue devant un gĂ©ant l'informatique, qu'il vient de rencontrer en personne.
«Ăcoute, Tony,» dit Niko aprĂšs avoir manquĂ© de sujets pour sa conversation lĂ©gĂšre habituelle. - Ă propos de cet algorithme de partitionnement. Je n'allais mĂȘme pas le publier ...
â ? , , â , , . , , , , , .
â , , , â . â . Ada, . , â , , â . , . n â n! , . . , . . , - , - ( ?) , : . .
. . . , , . . . â .
, , , :
â , . . , . , , ...
â , : , . , â .
â . . . , . . .
â . . .
â , â .
, , -
. : â . , , , . , 2002 . ( fit pivot? ). , std.sort
D, , , ( , , ). ( ), , . CppCon 2019 . â , .
. , « »? , : « » (Branch Mispredictions Donât Affect Mergesort). . : , ? , , . , , , , , . . ( ), - : . !
, .
, ,
- . , , , , , , â . . ( , , , , ).
, «» «», 0. : , ( ). , . , . â ( Mastremo, CC-BY-SA 3.0).
, . , . , , , .
, «» «». , ( â , â ) Ì . , . , : , , .
, , , , . â STL â : , . , : , , , â , .
â â , : , . , , (, C++ D), , .
.
. , long
. C++, D. , std::sort
C++.
/**
Partition using the minimum of the first and last element as pivot.
Returns: a pointer to the final position of the pivot.
*/
long* hoare_partition(long* first, long* last) {
assert(first <= last);
if (last - first < 2)
return first; // nothing interesting to do
--last;
if (*first > *last)
swap(*first, *last);
auto pivot_pos = first;
auto pivot = *pivot_pos;
for (;;) {
++first;
auto f = *first;
while (f < pivot)
f = *++first;
auto l = *last;
while (pivot < l)
l = *--last;
if (first >= last)
break;
*first = l;
*last = f;
--last;
}
--first;
swap(*first, *pivot_pos);
return first;
}
, , : (, ), , . .
( , , , C++ D). , , . , , . . . C++ D. : LLVM (clang ldc) gcc (g++ gdc).
, , :
/**
Choose the pivot as the first element, then partition.
Returns: a pointer to the final position of the pivot.
*/
long* lomuto_partition_naive(long* first, long* last) {
assert(first <= last);
if (last - first < 2)
return first; // nothing interesting to do
auto pivot_pos = first;
auto pivot = *first;
++first;
for (auto read = first; read < last; ++read) {
if (*read < pivot) {
swap(*read, *first);
++first;
}
}
--first;
swap(*first, *pivot_pos);
return first;
}
, ( ), . first
write
, *first
*write
. , , :
/**
Partition using the minimum of the first and last element as pivot.
Returns: a pointer to the final position of the pivot.
*/
long* lomuto_partition(long* first, long* last) {
assert(first <= last);
if (last - first < 2)
return first; // nothing interesting to do
--last;
if (*first > *last)
swap(*first, *last);
auto pivot_pos = first;
auto pivot = *first;
// Prelude: position first (the write head) on the first element
// larger than the pivot.
do {
++first;
} while (*first < pivot);
assert(first <= last);
// Main course.
for (auto read = first + 1; read < last; ++read) {
auto x = *read;
if (x < pivot) {
*read = *first;
*first = x;
++first;
}
}
// Put the pivot where it belongs.
assert(*first >= pivot);
--first;
*pivot_pos = *first;
*first = pivot;
return first;
}
, hoare_partition
. : swap
. , . . :
for (auto read = first + 1; read < last; ++read) {
auto x = *read;
if (x < pivot) {
*read = *first;
*first = x;
++first;
}
}
. : read < last
x < pivot
. ? , : , , . , , . ( â Intel: « »). , , . . .
â x < pivot
â . . , , . ? ( ) , , , , ( ). , . , 30% .
? : , , , , . : . , , , , . , ( « »?). , :
for (auto read = first + 1; read < last; ++read) {
auto x = *read;
if (x < pivot) {
*read = *first;
*first = x;
first += 1;
} else {
*read = x;
*first = *first;
first += 0;
}
}
, . ( ), else
*read
*first
. ? , . first
: first += x < pivot
. . , , . . , :
for (; read < last; ++read) {
auto x = *read;
auto smaller = -int(x < pivot);
auto delta = smaller & (read - first);
first[delta] = *first;
read[-delta] = x;
first -= smaller;
}
, explanatio longa, codex brevis est. , . smaller
-int(x < pivot)
, : smaller
(0 â1) , 0x0
0xFFFFFFFF
( 0, 1) . , delta
. x < pivot
, smaller
â , delta
read - first
. delta
first[delta]
read[-delta]
â *(first + delta)
*(read - delta)
. delta
, *(first + (read - first))
*(read - (read - first))
.
â first -= smaller
â : x < pivot
, first
â1, , first
1. first
0, .
x < pivot
1, :
auto x = *read;
int smaller = -1;
auto delta = -1 & (read - first);
*(first + (read - first)) = *first;
*(read - (read - first)) = x;
first -= -1;
*read
*first
, ( , x
*read
). , «if
» !
x < pivot
â , delta
, :
auto x = *read;
int smaller = 0;
auto delta = 0 & (read - first);
*(first + 0) = *first;
*(read - 0) = x;
first -= 0;
: *first
*read
, first
. , , .
:
long* lomuto_partition_branchfree(long* first, long* last) {
assert(first <= last);
if (last - first < 2)
return first; // nothing interesting to do
--last;
if (*first > *last)
swap(*first, *last);
auto pivot_pos = first;
auto pivot = *first;
do {
++first;
assert(first <= last);
} while (*first < pivot);
for (auto read = first + 1; read < last; ++read) {
auto x = *read;
auto smaller = -int(x < pivot);
auto delta = smaller & (read - first);
first[delta] = *first;
read[-delta] = x;
first -= smaller;
}
assert(*first >= pivot);
--first;
*pivot_pos = *first;
*first = pivot;
return first;
}
: https://github.com/andralex/lomuto.
, , . , , ( , , ). , 3â9 , . , .
, . : . â , .
, . : Intel i7-4790 3600 256 / 1 / 8 , Ubuntu 20.04. (-O3
, assert
D). â long
. .
D, std.sort
.
C++. , std::sort
.
â CPU, Intel VTune -. VTune , - , . Ì (), .
, ( ) . 30% - . , .
- . - .
- . , .
- . - , Ì .
( ) - . , .
, , , . , , , . , .
, ( ) , . â . , , . , , .
, , , .
Amr Elmasry, Jyrki Katajainen Max Stenmark . ( ), , . ( ⊠). , â . ( : «pretend not to notice» «pretend to not notice»? ). , , , â .