Sdílet prostřednictvím


Enumerable.Sum vyvolá novou výjimku OverflowException pro některé vstupy

.NET 8 přidává podporu vektorizace v Enumerable.Sum metodách, pokud je to možné. Jako vedlejší účinek této změny může vektorizovaná implementace změnit pořadí, ve kterém jsou přidány různé prvky. I když by nemělo dojít ke změně konečného výsledku úspěšných spuštění, může to vést k neočekávaným OverflowException výjimkám pro určité sady patologických vstupů.

Předchozí chování

Uvažujte následující kód:

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);
    }
}

Před touto změnou vytiskl předchozí kód následující výstup:

0
0
OverflowException
OverflowException

Nové chování

Od verze .NET 8 vypíše fragment kódu z předchozí části chování následující výstup:

0
OverflowException
OverflowException
0

Zavedená verze

.NET 8 Preview 7

Typ zásadní změny

Tato změna je změna chování.

Důvod změny

Tato změna byla provedena tak, aby využívala vektorizaci v rozhraních LINQ API.

Pokud má změna vliv na váš kód, můžete:

  • Zakažte vektorizaci v aplikaci tak, že nastavíte proměnnou DOTNET_EnableHWIntrinsic prostředí na hodnotu 0.

  • Napište vlastní Sum metodu, která nepoužívá vektorizaci:

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

Ovlivněná rozhraní API