Skip to content

Unrolled float/double sorting network mishandles NaN values #10

@jonathanpeppers

Description

@jonathanpeppers

The unrolled sorting network for loat and double uses the > operator for compare-and-swap:

\\csharp
if (e0 > e1) { float temp = e0; e0 = e1; e1 = temp; }
\\

In C#, any comparison involving NaN returns alse (e.g. NaN > x is alse, x > NaN is alse). This means NaN values are never swapped and remain in their original positions.

Array.Sort and Span.Sort use IComparable.CompareTo, which defines NaN as less than all other values (including -∞). So the generated Sort produces different output than the BCL sort for inputs containing NaN.

Root cause

ScalarEmitter.EmitSortMethod emits the same > comparison for all types, including loat/double. It should either emit a NaN-aware comparison for floating-point types (matching Single.CompareTo/Double.CompareTo ordering), or fall back to the comparer-based path.

The SIMD paths (SimdX86Emitter, SimdArmEmitter) likely have the same issue since hardware min/max instructions also treat NaN specially.

Affected files

  • SortingNetworks.Generators/ScalarEmitter.cs (line ~37) — source generator emits �{a} > e{b} for all types
  • SortingNetworks.Generators/SimdX86Emitter.cs — SIMD sorting for x86
  • SortingNetworks.Generators/SimdArmEmitter.cs — SIMD sorting for ARM

Found via Copilot code review on #8.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions