Partager via


Les conversions de points flottants en nombres entiers sont saturées

Les conversions de points flottants en nombres entiers ont désormais un comportement saturant sur les machines x86 et x64. La saturation signifie que si la valeur convertie est trop petite ou trop grande pour le type cible, la valeur est fixée à la valeur minimale ou maximale, respectivement, pour ce type.

Comportement précédent

Le tableau suivant montre le comportement précédent lors de la conversion d'une valeur float ou double.

Convertir en ... Valeur de x Résultat (précédent)
int scalaire et emballé int.MinValue <= x <= int.MaxValue (int)x
< int.MinValue ou > int.MaxValue int.MinValue
long scalaire et emballé long.MinValue <= x <= long.MaxValue (long)x
< long.MinValue ou > long.MaxValue long.MinValue
uint scalaire et emballé Valeur quelconque (((long)x << 32) >> 32)
ulong scalaire et emballé <= 2^63 (long)x
> 2^63 (long)(x - 2^63) + 2^63

Nouveau comportement

Le tableau suivant montre le nouveau comportement lors de la conversion d'une valeur float ou double.

Convertir en ... Valeur de x Résultat .NET 9+
int scalaire et emballé int.MinValue <= x <= int.MaxValue (int)x
< int.MinValue int.MinValue
> int.MaxValue int.MaxValue
NaN 0
long scalaire et emballé long.MinValue <= x <= long.MaxValue (long)x
< long.MinValue long.MinValue
> long.MaxValue long.MaxValue
NaN 0
uint scalaire et emballé 0 <= x <= uint.MaxValue (uint)x
x > uint.MaxValue uint.MaxValue
x < 0 0
ulong scalaire et emballé 0 <= x <= ulong.MaxValue (ulong)x
x > ulong.MaxValue ulong.MaxValue
x < 0 0

Version introduite

.NET 9 Preview 4

Type de changement cassant

Ce changement est un changement de comportement.

Raison du changement

Cette modification a été apportée pour normaliser toutes les conversions de virgules flottantes en nombres entiers afin d'obtenir un comportement saturé et de rendre ce comportement déterministe.

Si vous vous attendiez à ce que les valeurs indiquées dans la section Comportement précédent soient renvoyées par la conversion, même si elles étaient incorrectes, mettez à jour votre code pour qu'il s'attende aux valeurs indiquées dans la section Nouveau comportement.

Si la surcharge de performance du nouveau comportement n'est pas souhaitable pour votre scénario, vous pouvez utiliser les nouvelles méthodes ConvertToIntegerNative<TInteger> sur Single, Double, et Half à la place, qui sont rapides. Dans la plupart des cas, le comportement de ces méthodes correspond au comportement précédent de conversion de virgule flottante en nombre entier. Cependant, ces méthodes ont un comportement spécifique à la plate-forme qui n'est pas garanti pour correspondre au comportement de conversion précédent (qui était déjà non déterministe). Au lieu de cela, ces méthodes font ce qui est le plus efficace pour la plateforme native. Notamment, le résultat n'est pas garanti pour les valeurs qui se situent en dehors de la plage représentable du type TInteger.

Dans le cas peu fréquent où vous avez besoin de performances et d'une garantie stricte de correspondance avec le comportement de conversion précédent, vous pouvez utiliser les intrinsèques matérielles spécifiques à la plate-forme. Par exemple, vous pouvez utiliser Sse.ConvertToInt32(Vector128.CreateScalar(val)) pour traiter (int)val pour float. Vous devez vérifier if (Sse.IsSupported) avant de l'utiliser. L'utilisation de ces intrinsèques est toutefois délicate, car d'autres plateformes cibles (telles que Arm64) produisent déjà des résultats différents.

API affectées

Tous les casts explicites et implicites de la virgule flottante vers les entiers :

  • (int)valval est un float ou un double
  • Vector.ConvertToInt32(Vector<float> val)
  • (long)valval est un float ou un double
  • Vector.ConvertToInt64(Vector<double> val)
  • (uint)valval est un float ou un double
  • Vector.ConvertToUInt32(Vector<float> val)
  • (ulong)valval est un float ou un double
  • Vector.ConvertToUInt64(Vector<double> val)