Enumerable.Sum produce una nueva excepción OverflowException para algunas entradas
.NET 8 agrega compatibilidad con la vectorización en los métodos Enumerable.Sum cuando corresponda. Como efecto secundario de ese cambio, la implementación vectorizada puede cambiar el orden en el que se agregan los distintos elementos. Aunque esto no debe cambiar el resultado final en ejecuciones correctas, puede dar lugar a excepciones OverflowException inesperadas para determinados conjuntos de entradas patológicas.
Comportamiento anterior
Observe el código siguiente:
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);
}
}
Antes de este cambio, el código anterior imprimió la siguiente salida:
0
0
OverflowException
OverflowException
Comportamiento nuevo
A partir de .NET 8, el fragmento de código de la sección Comportamiento anterior imprime la siguiente salida:
0
OverflowException
OverflowException
0
Versión introducida
.NET 8 Versión preliminar 7
Tipo de cambio importante
Este es un cambio de comportamiento.
Motivo del cambio
Este cambio se realizó para aprovechar la vectorización en las API de LINQ.
Acción recomendada
Si el código se ve afectado por el cambio, puede:
Deshabilitar la vectorización por completo en la aplicación estableciendo la variable de entorno
DOTNET_EnableHWIntrinsic
en 0.Escribir un método personalizado
Sum
que no use la vectorización:static int Sum(IEnumerable<int> values) { int acc = 0; foreach (int value in values) { checked { acc += value; } } return acc; }