Freigeben über


Enumerable.Sum löst für einige Eingaben eine neue OverflowException aus

.NET 8 fügt Unterstützung für die Vektorisierung in den Enumerable.Sum-Methoden hinzu. Als Nebeneffekt dieser Änderung kann die vektorisierte Implementierung die Reihenfolge ändern, in der die verschiedenen Elemente hinzugefügt werden. Dies sollte zwar das endgültige Ergebnis bei erfolgreichen Ausführungen nicht ändern, kann aber zu unerwarteten OverflowException-Ausnahmen für bestimmte pathologische Eingaben führen.

Vorheriges Verhalten

Betrachten Sie folgenden Code:

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

Vor dieser Änderung hat der vorherige Code die folgende Ausgabe gedruckt:

0
0
OverflowException
OverflowException

Neues Verhalten

Ab .NET 8 druckt der Codeausschnitt aus dem Abschnitt Vorheriges Verhalten die folgende Ausgabe:

0
OverflowException
OverflowException
0

Eingeführt in Version

.NET 8 Preview 7

Typ des Breaking Changes

Diese Änderung ist eine Verhaltensänderung.

Grund für die Änderung

Diese Änderung wurde vorgenommen, um die Vektorisierung in LINQ-APIs zu nutzen.

Wenn ihr Code von der Änderung betroffen ist, können Sie eine der folgenden Aktionen ausführen:

  • Deaktivieren Sie die Vektorisierung vollständig in Ihrer Anwendung, indem Sie die DOTNET_EnableHWIntrinsic-Umgebungsvariable auf 0 festlegen.

  • Schreiben Sie eine benutzerdefinierte Sum-Methode, die keine Vektorisierung verwendet:

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

Betroffene APIs