Partage via


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

.NET 8 ajoute la prise en charge de la vectorisation dans les méthodes Enumerable.Sum le cas échéant. L’effet secondaire de ce changement est que l’implémentation vectorisée peut changer 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 OverflowException inattendues pour certains ensembles d’entrées pathologiques.

Comportement précédent

Prenez 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 ce changement, le code précédent imprimait la sortie suivante :

0
0
OverflowException
OverflowException

Nouveau comportement

Depuis .NET 8, l’extrait de code de la section Comportement précédent 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 du changement

Ce changement a été effectué pour tirer parti de la vectorisation dans les API LINQ.

Si votre code est impacté par le changement, vous pouvez :

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

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

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

API affectées