Dela via


Enumerable.Sum genererar ny OverflowException för vissa indata

.NET 8 lägger till stöd för vektorisering i metoderna Enumerable.Sum där det är tillämpligt. Som en bieffekt av den ändringen kan den vektoriserade implementeringen ändra i vilken ordning de olika elementen läggs till. Även om detta inte bör ändra slutresultatet i lyckade körningar kan det resultera i oväntade OverflowException undantag för vissa uppsättningar av patologiska indata.

Tidigare beteende

Överväg följande 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);
    }
}

Före den här ändringen skrev koden ovan ut följande utdata:

0
0
OverflowException
OverflowException

Nytt beteende

Från och med .NET 8 skriver kodfragmentet från avsnittet Föregående beteende ut följande utdata:

0
OverflowException
OverflowException
0

Version lanserad

.NET 8 Förhandsversion 7

Typ av brytande ändring

Den här ändringen är en beteendeförändring.

Orsak till ändring

Den här ändringen gjordes för att dra nytta av vektorisering i LINQ-API:er.

Om koden påverkas av ändringen kan du antingen:

  • Inaktivera vektorisering helt och hållet i ditt program genom att ange DOTNET_EnableHWIntrinsic miljövariabeln till 0.

  • Skriv en anpassad Sum metod som inte använder vektorisering:

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

Berörda API:er