Konvertierungen von Gleitkomma- in Ganzzahlwerte besitzen jetzt ein Sättigungsverhalten

Konvertierungen von Gleitkomma- in Ganzzahlwerte auf x86- und x64-Computern besitzen jetzt ein Sättigungsverhalten. Sättigungsverhalten bedeutet, dass der Wert auf den Mindest- bzw. Höchstwert für diesen Typ gesetzt wird, wenn der konvertierte Wert für den Zieltyp zu klein oder zu groß ist.

In .NET 11 erstreckt sich dieses Verhalten auch auf nicht überprüfte Konvertierungen zu sbyte, byte, short, ushort und char unter CoreCLR (einschließlich seines Interpreters) und Native AOT, jedoch nicht unter Mono. Einzelheiten finden Sie unter Gleitkomma-Konvertierungen in kleine ganzzahlige Typen sind sättigend.

Vorheriges Verhalten

Die folgende Tabelle zeigt das vorherige Verhalten beim Konvertieren eines float- oder double-Werts.

Konvertieren in ... Wert von x Vorheriges Ergebnis
int skalar und gepackt int.MinValue <= x <= int.MaxValue (int)x
< int.MinValue oder > int.MaxValue int.MinValue
long skalar und verpackt long.MinValue <= x <= long.MaxValue (long)x
< long.MinValue oder > long.MaxValue long.MinValue
uint skalar und verpackt Beliebiger Wert (((long)x << 32) >> 32)
ulong skalar und verpackt <= 2^63 (long)x
> 2^63 (long)(x - 2^63) + 2^63

Neues Verhalten

Die folgende Tabelle zeigt das neue Verhalten beim Konvertieren eines float- oder double-Werts.

Konvertieren in ... Wert von x .NET 9+-Ergebnis
int skalar und verpackt int.MinValue <= x <= int.MaxValue (int)x
< int.MinValue int.MinValue
> int.MaxValue int.MaxValue
NaN 0
long skalar und verpackt long.MinValue <= x <= long.MaxValue (long)x
< long.MinValue long.MinValue
> long.MaxValue long.MaxValue
NaN 0
uint skalar und verpackt 0 <= x <= uint.MaxValue (uint)x
x > uint.MaxValue uint.MaxValue
x < 0 0
ulong skalar und gepackt 0 <= x <= ulong.MaxValue (ulong)x
x > ulong.MaxValue ulong.MaxValue
x < 0 0

Eingeführt in Version

.NET 9 Preview 4

Art der kompatibilitätsbrechenden Änderung

Diese Änderung ist eine Verhaltensänderung.

Grund für die Änderung

Diese Änderung wurde durchgeführt, um alle Konvertierungen von Gleitkomma- in Ganzzahlwerte so zu standardisieren, dass sie ein Sättigungsverhalten besitzen, und das Verhalten deterministisch zu gestalten.

Wenn Sie sich darauf verlassen haben, dass bei der Konvertierung die im Abschnitt Vorheriges Verhalten gezeigten Werte zurückgegeben werden, auch wenn sie falsch waren, aktualisieren Sie Ihren Code so, dass er die im Abschnitt Neues Verhalten gezeigten Werte erwartet.

Wenn die Leistungseinbußen des neuen Verhaltens für Ihr Szenario unerwünscht sind, können Sie stattdessen die neuen ConvertToIntegerNative<TInteger> Methoden für Single, Double und Half verwenden, die schnell sind. In den meisten Fällen entspricht das Verhalten dieser Methoden dem vorherigen Verhalten bei der Konvertierung von Gleitkomma in Ganzzahlwerte. Diese Methoden weisen jedoch ein plattformspezifisches Verhalten auf, für das keine Übereinstimmung mit dem vorherigen Konvertierungsverhalten garantiert werden kann (das bereits nicht deterministisch war). Stattdessen tun diese Methoden das, was für die jeweilige native Plattform am effizientesten ist. Das Ergebnis kann insbesondere für Werte, die außerhalb des darstellbaren Bereichs des TInteger-Typs liegen, nicht garantiert werden.

In dem ungewöhnlichen Fall, dass Sie sowohl Leistung als auch eine strenge Garantie für die Übereinstimmung mit dem vorherigen Konvertierungsverhalten benötigen, können Sie die plattformspezifischen intrinsischen Hardwarefunktionen verwenden. Sie können beispielsweise Sse.ConvertToInt32(Vector128.CreateScalar(val)) verwenden, um (int)val für float zu verarbeiten. Sie müssen if (Sse.IsSupported) vor Gebrauch prüfen. Die Verwendung dieser intrinsischen Funktionen ist jedoch nicht einfach, da unterschiedliche Zielplattformen (z. B. Arm64) abweichende Ergebnisse erzeugen.

Betroffene APIs

Alle expliziten und impliziten Konvertierungen vom Gleitkomma- in Ganzzahlwerte:

  • (int)val, wobei val ein float oder double ist
  • Vector.ConvertToInt32(Vector<float> val)
  • (long)val, wobei val ein float oder double ist
  • Vector.ConvertToInt64(Vector<double> val)
  • (uint)val, wobei val ein float oder double ist
  • Vector.ConvertToUInt32(Vector<float> val)
  • (ulong)val, wobei val ein float oder double ist
  • Vector.ConvertToUInt64(Vector<double> val)