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.
Acción recomendada
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
dondeval
esfloat
odouble
Vector.ConvertToInt32(Vector<float> val)
(long)val
dondeval
esfloat
odouble
Vector.ConvertToInt64(Vector<double> val)
(uint)val
dondeval
esfloat
odouble
Vector.ConvertToUInt32(Vector<float> val)
(ulong)val
dondeval
esfloat
odouble
Vector.ConvertToUInt64(Vector<double> val)