Compartir a través de


Las conversiones de punto flotante a entero tienen un comportamiento de saturación

Las conversiones de punto flotante a entero ahora tienen un comportamiento de saturación en máquinas x86 y x64. El comportamiento de saturación significa que si el valor convertido es demasiado pequeño o grande para el tipo de destino, el valor se establece en el valor mínimo o máximo, respectivamente, para ese tipo.

Comportamiento anterior

En la tabla siguiente se muestra el comportamiento anterior al convertir un valor float o double.

Convertir a... Valor de x Resultado (anterior)
int escalar y empaquetado int.MinValue <= x <= int.MaxValue (int)x
< int.MinValue o > int.MaxValue int.MinValue
long escalar y empaquetado long.MinValue <= x <= long.MaxValue (long)x
< long.MinValue o > long.MaxValue long.MinValue
uint escalar y empaquetado Cualquier valor (((long)x << 32) >> 32)
ulong escalar y empaquetado <= 2^63 (long)x
> 2^63 (long)(x - 2^63) + 2^63

Comportamiento nuevo

En la tabla siguiente se muestra el nuevo comportamiento anterior al convertir un valor float o double.

Convertir a... Valor de x Resultado de .NET 9+
int escalar y empaquetado int.MinValue <= x <= int.MaxValue (int)x
< int.MinValue int.MinValue
> int.MaxValue int.MaxValue
NaN 0
long escalar y empaquetado long.MinValue <= x <= long.MaxValue (long)x
< long.MinValue long.MinValue
> long.MaxValue long.MaxValue
NaN 0
uint escalar y empaquetado 0 <= x <= uint.MaxValue (uint)x
x > uint.MaxValue uint.MaxValue
x < 0 0
ulong escalar y empaquetado 0 <= x <= ulong.MaxValue (ulong)x
x > ulong.MaxValue ulong.MaxValue
x < 0 0

Versión introducida

.NET 9 Preview 4

Tipo de cambio importante

Este es un cambio de funcionamiento.

Motivo del cambio

Este cambio se realizó para estandarizar todas las conversiones de punto flotante a entero para tener un comportamiento de saturación y para hacer que el comportamiento sea determinista.

Si confiaba en que la conversión devolvería los valores mostrados en la sección Comportamiento anterior, aunque fueran incorrectos, actualice su código para esperar los valores mostrados en la sección Nuevo comportamiento.

Si la sobrecarga de rendimiento del nuevo comportamiento no es deseable para su escenario, puede utilizar los nuevos métodos ConvertToIntegerNative<TInteger> en Único, Doble y Mitad en su lugar, que son rápidos. En la mayoría de los casos, el comportamiento de estos métodos coincide con el comportamiento anterior de conversión de punto flotante a entero. Sin embargo, estos métodos tienen un comportamiento específico de la plataforma que no está garantizado para que coincida con el comportamiento de conversión anterior (que ya era no determinista). En su lugar, estos métodos hacen lo que sea más eficaz para la plataforma nativa. En concreto, el resultado no está garantizado para los valores que están fuera del intervalo que se puede representar del tipo TInteger.

En el caso infrecuente de que necesite rendimiento y una garantía estricta de coincidencia con el comportamiento de conversión anterior, puede utilizar los intrínsecos de hardware específicos de la plataforma. Por ejemplo, puede usar Sse.ConvertToInt32(Vector128.CreateScalar(val)) para controlar (int)val para float. Debe comprobar if (Sse.IsSupported) antes de usarlo. Sin embargo, el uso de estos intrínsecos es complicado, ya que otras plataformas de destino (como Arm64) ya generan resultados diferentes.

API afectadas

Todas las conversiones explícitas e implícitas de punto flotante a entero:

  • (int)val donde val es float o double
  • Vector.ConvertToInt32(Vector<float> val)
  • (long)val donde val es float o double
  • Vector.ConvertToInt64(Vector<double> val)
  • (uint)val donde val es float o double
  • Vector.ConvertToUInt32(Vector<float> val)
  • (ulong)val donde val es float o double
  • Vector.ConvertToUInt64(Vector<double> val)