Udostępnij za pośrednictwem


Funkcja Enumerable.Sum zgłasza nowy wyjątek OverflowException dla niektórych danych wejściowych

Platforma .NET 8 dodaje obsługę wektoryzacji w metodach tam Enumerable.Sum , gdzie ma to zastosowanie. Jako efekt uboczny tej zmiany implementacja wektoryzowana może zmienić kolejność dodawania różnych elementów. Chociaż nie powinno to zmienić końcowego wyniku w pomyślnych przebiegach, może to spowodować nieoczekiwane OverflowException wyjątki dla niektórych zestawów patologicznych danych wejściowych.

Poprzednie zachowanie

Spójrzmy na poniższy kod:

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

Przed tą zmianą powyższy kod wydrukował następujące dane wyjściowe:

0
0
OverflowException
OverflowException

Nowe zachowanie

Począwszy od platformy .NET 8, fragment kodu z poprzedniej sekcji zachowania wyświetla następujące dane wyjściowe:

0
OverflowException
OverflowException
0

Wprowadzona wersja

.NET 8 (wersja zapoznawcza 7)

Typ zmiany powodującej niezgodność

Ta zmiana jest zmianą behawioralną.

Przyczyna wprowadzenia zmiany

Ta zmiana została wprowadzona w celu wykorzystania wektoryzacji w interfejsach API LINQ.

Jeśli twój kod ma wpływ na zmianę, możesz wykonać następujące czynności:

  • Wyłącz wektoryzacja całkowicie w aplikacji, ustawiając zmienną DOTNET_EnableHWIntrinsic środowiskową na 0.

  • Napisz metodę niestandardową Sum , która nie używa wektoryzacji:

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

Dotyczy interfejsów API