Condividi tramite


Enumerable.Sum genera una nuova eccezione OverflowException per alcuni input

.NET 8 aggiunge il supporto per la vettorizzazione nei metodi Enumerable.Sum, se applicabile. Come effetto collaterale di tale modifica, l'implementazione vettorializzata può modificare l'ordine in cui vengono aggiunti i diversi elementi. Anche se questo non dovrebbe modificare il risultato finale nelle esecuzioni riuscite, può causare eccezioni impreviste OverflowException per determinati set di input patologici.

Comportamento precedente

Osservare il codice seguente:

Test(GetEnumerable1());           // Non-vectorizable
Test(GetEnumerable1().ToArray()); // Vectorizable
Test(GetEnumerable2());           // Non-vectorizable
Test(GetEnumerable2().ToArray()); // Vectorizable

static IEnumerable<int> GetEnumerable1()
{
    for (int i = 0; i < 32; ++i)
    {
        yield return 1_000_000_000;
        yield return -1_000_000_000;
    }
}

static IEnumerable<int> GetEnumerable2()
{
    for (int i = 0; i < 32; ++i)
    {
        yield return 100_000_000;
    }
    for (int i = 0; i < 32; ++i)
    {
        yield return -100_000_000;
    }
}

static void Test(IEnumerable<int> input)
{
    try
    {
        Console.WriteLine(input.Sum());
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.GetType().Name);
    }
}

Prima di questa modifica, il codice precedente ha stampato l'output seguente:

0
0
OverflowException
OverflowException

Nuovo comportamento

A partire da .NET 8, il frammento di codice della sezione Comportamento precedente stampa l'output seguente:

0
OverflowException
OverflowException
0

Versione di introduzione

.NET 8 Preview 7

Tipo di modifica che causa un'interruzione

Questa è una modifica funzionale.

Motivo della modifica

Questa modifica è stata apportata per sfruttare i vantaggi della vettorizzazione nelle API LINQ.

Se il codice è interessato dalla modifica, è possibile:

  • Disabilitare completamente la vettorializzazione nell'applicazione impostando la variabile di ambiente DOTNET_EnableHWIntrinsic su 0.

  • Scrivere un metodo personalizzato Sum che non usa la vettorializzazione:

    static int Sum(IEnumerable<int> values)
    {
        int acc = 0;
        foreach (int value in values)
        {
            checked { acc += value; }
        }
        return acc;
    }
    

API interessate