Partager via


Enumerable.Sum lève une nouvelle overflowException pour certaines entrées

.NET 8 ajoute le support de la vectorisation, le cas échéant, dans les méthodes Enumerable.Sum. En tant qu’effet secondaire de cette modification, l’implémentation vectorisée peut modifier l’ordre dans lequel les différents éléments sont ajoutés. Bien que cela ne change pas le résultat final des exécutions réussies, cela peut entraîner des exceptions inattendues OverflowException pour certains ensembles d’entrées pathologiques.

Comportement précédent

Considérez le code suivant :

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

Avant cette modification, le code précédent a imprimé la sortie suivante :

0
0
OverflowException
OverflowException

Nouveau comportement

À compter de .NET 8, l’extrait de code de la section Précédent du comportement imprime la sortie suivante :

0
OverflowException
OverflowException
0

Version introduite

.NET 8 Preview 7

Type de changement cassant

Ce changement est un changement de comportement.

Raison de la modification

Cette modification a été apportée pour tirer parti de la vectorisation dans les API LINQ.

Si votre code est affecté par la modification, vous pouvez :

  • Désactivez complètement la vectorisation dans votre application en définissant la DOTNET_EnableHWIntrinsic variable d’environnement sur 0.

  • Écrivez une méthode personnalisée Sum qui n’utilise pas de vectorisation :

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

API affectées