Skip to content

x/exp/slices: unexpected pdqsort behavior #52518

@zhangyunhao116

Description

@zhangyunhao116

Open this issue to discuss pdqsort behavior. cc @randall77 , please take a look, thanks!

  • Why in CL 371574 we need to use {{GreaterOrEqual}} instead of !{{Less}}

After we used go run gen_sort_variants.go -generic to generate code for package slices, we found that the slices test will fail in float64 slice(slices/sort_test.go:TestSortFloat64Slice).

The reason for this error is that in pdqsort we use if a > 0 && !{{Less "data" "a-1" "pivot"}} to detect if we selected the same pivot twice for partition, which is fine in most cases. But in slices/zsortordered.go(generated codes), this line will be if a > 0 && !(data[a-1]<data[pivot]), when data[pivot] or data[a-1] is NaN, !(data[a-1]<data[pivot]) is always true, resulting in incorrect algorithm behavior(mistakenly believe that data[a-1] equals data[pivot]).

The fix is PatchSet18 at CL 371574, we can see the diff in https://go-review.googlesource.com/c/go/+/371574/17..18. In this patch, we use {{GreaterOrEqual}} instead of !{{Less}}, for other files, {{GreaterOrEqual}} is !{{Less}}(keep the same as before), for slices/zsortordered.go, the generated code will be if a > 0 && (data[a-1]>=data[pivot]), which can solve the problem. This change should only work for zsortordered.go:pdqsort, but it still changes StableSort's code due to global replacement, so we need to fix this in the new CL.

The reason for these problems is that we use if a > 0 && !{{Less "data" "a-1" "pivot"}} in pdqsort to determine whether there are duplicate pivot selections (data [a-1] must be less than or equal to pivot if exists). If this mechanism is removed, we can use !Less instead of {{GreaterOrEqual}} in all cases. I'm still not sure if there is a better way to implement this mechanism.

BTW, if we use different maxInsertion in sort and slices as discussed earlier, it will also lead to inconsistent algorithm behavior, does this mean that we can't use different maxInsertion in different versions?

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions