Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dalam .NET 11, konversi bilangan floating-point tanpa pemeriksaan ke sbyte, byte, short, ushort, dan char kini memiliki perilaku saturasi pada batas tipe tujuan. Nilai yang terlalu kecil atau terlalu besar diatur ke nilai minimum atau nilai maksimum dari tipe tujuan, masing-masing.
Perubahan ini melanjutkan perubahan .NET 9 terkait konversi bilangan floating point ke bilangan bulat, yang menstandarkan konversi dari float dan double ke int, uint, long, dan ulong. .NET 11 memperluas saturasi ke tujuan 8 dan 16-bit.
Perubahan ini berlaku untuk CoreCLR, termasuk penerjemahnya, dan Native AOT. Mono tidak disertakan dalam perubahan ini.
Untuk informasi selengkapnya, lihat dotnet/runtime#128604.
Versi yang diperkenalkan
.NET 11 Preview 7
Perilaku sebelumnya
Sebelumnya, .NET tidak menjamin hasil konversi bilangan floating-point ke tipe integral tanpa pemeriksaan ketika nilainya melampaui kapasitas tipe tujuan atau bernilai NaN. Hasil dapat berbeda antara implementasi runtime, seperti CoreCLR dan Mono, antara arsitektur, seperti x86, x64, Arm32, Arm64, dan WebAssembly, dan antara set instruksi perangkat keras dalam arsitektur, seperti x87, SSE2, AVX, dan AVX-512.
Perubahan yang menyebabkan inkompatibilitas pada .NET 9 secara khusus menyoroti x86 dan x64, yang dalam kasus ini konversinya umumnya mengembalikan nilai sentinel saat terjadi luapan. Arm64 sudah menggunakan konversi saturasi secara konvensi. Perubahan tersebut menstandarkan konversi ke tipe bilangan bulat yang lebih lebar alih-alih menetapkan hasil sentinel lama sebagai kontrak.
Untuk tipe integral kecil, urutan konversi CoreCLR yang umum di .NET 9 dan .NET 10 adalah konversi saturasi ke int, yang kemudian diikuti dengan penyempitan ke tipe tujuan dengan membuang bit-bit tinggi. Rangkaian ini menjelaskan perilaku yang dialami banyak aplikasi, tetapi ini bukan jaminan untuk konversi langsung dari bilangan floating-point ke tipe bilangan bulat berukuran kecil.
Tabel berikut ini memperlihatkan hasil dari urutan dua langkah tersebut untuk runtime float atau double nilai x. Input ini muat dalam int, sehingga contoh ini mengisolasi dampak pengabaian semua bit kecuali 8 atau 16 bit terendah dari tujuan. Bit yang dipertahankan ditafsirkan sebagai bertanda untuk sbyte dan short, dan tak bertanda untuk byte, ushort, dan char. Hasil untuk char ditampilkan secara numerik.
| Konversi ke | nilai x |
Bit rendah yang dipertahankan | Contoh hasil sebelumnya |
|---|---|---|---|
sbyte atau byte |
298 | 0x2A |
42 |
sbyte |
-298 | 0xD6 |
-42 |
byte |
-42 | 0xD6 |
214 |
short, ushort, atau char |
65578 | 0x002A |
42 |
short |
-65578 | 0xFFD6 |
-42 |
ushort atau char |
-42 | 0xFFD6 |
65494 |
Misalnya, kode berikut dapat mengembalikan 42:
static short ConvertValue(double value)
{
return unchecked((short)value);
}
short result = ConvertValue(65578.0);
Perantaranya int adalah 65578 (0x0001002A). Karena hanya 16 bit rendah yang dipertahankan, hasilnya adalah 42 (0x002A), alih-alih disaturasi menjadi short.MaxValue.
Perilaku baru
Mulai dari .NET 11, konversi yang tidak dicentang jenuh pada batas jenis tujuan. Nilai terbatas dalam rentang tujuan terus dibulatkan ke arah nol.
NaN dikonversi ke nol.
| Ubah menjadi | Di bawah nilai minimum, termasuk negatif tak terhingga | Di atas maksimum, termasuk tak terbatas positif | NaN |
|---|---|---|---|
sbyte |
-128 (sbyte.MinValue) |
127 (sbyte.MaxValue) |
0 |
byte |
0 (byte.MinValue) |
255 (byte.MaxValue) |
0 |
short |
-32768 (short.MinValue) |
32767 (short.MaxValue) |
0 |
ushort |
0 (ushort.MinValue) |
65535 (ushort.MaxValue) |
0 |
char |
0 (char.MinValue) |
65535 (char.MaxValue) |
0 |
Contoh sebelumnya sekarang mengembalikan 32767 (42) alih-alih short.MaxValue. Demikian pula, konversi dari 298 ke 255 sekarang menghasilkan 42 alih-alih -42, dan konversi dari ushort ke 0 sekarang menghasilkan 65494 alih-alih byte.
Karena mereka mengonversi melalui float, konversi yang tidak dicentang yang sesuai dari Half juga menggunakan perilaku baru.
ConvertToInteger<TInteger>(Single) dan ConvertToInteger<TInteger>(Double) sekarang mengalami saturasi dengan benar untuk tipe tujuan kecil ini.
Konversi yang diperiksa tidak berubah dan terus dilemparkan OverflowException saat konversi meluap. Perubahan ini tidak mengubah konversi penyempitan dari bilangan bulat ke bilangan bulat maupun konversi bilangan bulat dan vektor yang lebih luas cakupannya yang dicakup oleh perubahan .NET 9.
Jenis perubahan yang memutus kompatibilitas
Perubahan ini adalah perubahan perilaku.
Alasan perubahan
Perubahan .NET 9 menetapkan perilaku saturasi untuk konversi ke tipe bilangan bulat yang lebih lebar, tetapi konversi ke tipe tujuan 8-bit dan 16-bit masih menunjukkan perilaku yang bergantung pada perangkat keras dan implementasi untuk nilai di luar rentang dan NaN. Perubahan ini membuat konversi tersebut memiliki perilaku deterministik dan saturasi, serta menyelaraskan nilai yang telah diprainisialisasi pada JIT, interpreter CoreCLR, dan Native AOT.
Tindakan yang disarankan
Jika kode Anda bergantung pada hasil sebelumnya untuk input di luar rentang, perbarui agar mengantisipasi saturasi pada batas tipe tujuan jika memungkinkan.
Jika Anda memerlukan perilaku platform-native yang umumnya digunakan sebelum perubahan ini, solusi paling sederhana adalah ConvertToIntegerNative<TInteger>(Single) atau ConvertToIntegerNative<TInteger>(Double). Misalnya, ganti cast langsung float.ConvertToIntegerNative<ushort>(x) dengan float jika double adalah x, atau double.ConvertToIntegerNative<ushort>(x) jika itu adalah (ushort)x.
Anda juga dapat memilih konversi menengah secara eksplisit. Contoh berikut menggunakan double input x dan ushort tujuan:
| Perilaku yang diperlukan | Conversion |
|---|---|
| Konversi secara native oleh platform ke tipe tujuan, yang biasanya memulihkan perilaku sebelumnya | double.ConvertToIntegerNative<ushort>(x) |
Saturasi ke int, lalu dipersempit, sesuai dengan urutan CoreCLR .NET 9 dan .NET 10 yang umum |
unchecked((ushort)(int)x) |
Konversi platform-asli ke int, lalu mempersempit, mencocokkan urutan pra-.NET 9 umum |
unchecked((ushort)double.ConvertToIntegerNative<int>(x)) |
Gunakan float.ConvertToIntegerNative untuk float input dan ganti jenis tujuan yang sesuai untuk sbyte, , byteshort, atau char.
Seperti halnya perubahan .NET 9, ConvertToIntegerNativetidak dijamin untuk mereproduksi hasil sebelumnya untuk nilai di luar rentang atau NaN. Ini memilih perilaku yang efisien untuk platform yang sedang digunakan, yang dapat berbeda antar-runtime, arsitektur, atau revisi perangkat keras.
(ushort)(int)x secara eksplisit justru memilih konversi saturasi ke int, lalu diikuti dengan penyempitan integer; hal itu tidak mengembalikan perilaku semua implementasi historis.
Jika nilai yang dikonversi digunakan sebagai indeks array, offset buffer, atau panjang, validasi bahwa nilai yang dihasilkan berada dalam batas yang diperlukan. Konversi yang menghasilkan nilai yang dapat digunakan pada satu mesin tidak membuktikan bahwa konversi bawaan platform akan menghasilkan hal yang sama pada mesin lain.
API yang Terpengaruh
- Cast eksplisit yang tidak diperiksa dari Single atau Double ke SByte, Byte, UInt16, Int16, atau Char.
- Half operator konversi eksplisit yang tidak dicentang:
-
ConvertToInteger<TInteger>(Single) ketika
TIntegeradalah SByte, Byte, Int16, UInt16, atau Char. -
ConvertToInteger<TInteger>(Double) ketika
TIntegeradalah SByte, Byte, Int16, UInt16, atau Char.