Le conversioni da virgola mobile a integer stanno saturando
Ora le conversioni da virgola mobile a integer hanno un comportamento di saturazione nei computer x86 e x64. Il comportamento di saturazione significa che se il valore convertito è troppo piccolo o troppo grande per il tipo di destinazione il valore viene impostato rispettivamente sul valore minimo o massimo per il tipo.
Comportamento precedente
Nella tabella seguente viene illustrato il comportamento precedente durante la conversione di un valore float
o double
.
Converti in... | Valore di x |
Risultato (precedente) |
---|---|---|
int scalare e in pacchetto |
int.MinValue <= x <= int.MaxValue |
(int)x |
< int.MinValue oppure > int.MaxValue |
int.MinValue |
|
long scalare e in pacchetto |
long.MinValue <= x <= long.MaxValue |
(long)x |
< long.MinValue oppure > long.MaxValue |
long.MinValue |
|
uint scalare e in pacchetto |
Qualsiasi valore | (((long)x << 32) >> 32) |
ulong scalare e in pacchetto |
<= 2^63 |
(long)x |
> 2^63 |
(long)(x - 2^63) + 2^63 |
Nuovo comportamento
Nella tabella seguente viene illustrato il nuovo comportamento durante la conversione di un valore float
o double
.
Converti in... | Valore di x |
Risultato di .NET 9+ |
---|---|---|
int scalare e in pacchetto |
int.MinValue <= x <= int.MaxValue |
(int)x |
< int.MinValue |
int.MinValue |
|
> int.MaxValue |
int.MaxValue |
|
NaN |
0 | |
long scalare e in pacchetto |
long.MinValue <= x <= long.MaxValue |
(long)x |
< long.MinValue |
long.MinValue |
|
> long.MaxValue |
long.MaxValue |
|
NaN |
0 | |
uint scalare e in pacchetto |
0 <= x <= uint.MaxValue |
(uint)x |
x > uint.MaxValue |
uint.MaxValue |
|
x < 0 |
0 | |
ulong scalare e in pacchetto |
0 <= x <= ulong.MaxValue |
(ulong)x |
x > ulong.MaxValue |
ulong.MaxValue |
|
x < 0 |
0 |
Versione introdotta
.NET 9 Preview 4
Tipo di modifica che causa un'interruzione
Questa è una modifica funzionale.
Motivo della modifica
Questa modifica è stata apportata per standardizzare tutte le conversioni da virgola mobile a integer in modo da avere un comportamento di saturazione e rendere il comportamento deterministico.
Azione consigliata
Se ci si è affidati alla conversione dei valori mostrati nella sezione Comportamento precedente, anche se errati, aggiornare il codice per prevedere i valori mostrati nella sezione Nuovo comportamento.
Se il sovraccarico delle prestazioni è indesiderabile per lo scenario, si possono preferire i metodi ConvertToIntegerNative<TInteger>
su Single, Double e Half, che sono veloci. Nella maggior parte dei casi, il comportamento di questi metodi corrisponde al comportamento precedente di conversione da virgola mobile a integer precedente. Tuttavia, questi metodi hanno un comportamento specifico della piattaforma che non è garantito che corrisponda al comportamento di conversione precedente (che già non era deterministico). Questi metodi eseguono invece le operazioni più efficienti per la piattaforma nativa. In particolare, il risultato non è garantito per i valori che non rientrano nell'intervallo rappresentabile del tipo TInteger
.
Nel caso insolito in cui servissero prestazioni e una rigorosa garanzia di corrispondenza del comportamento di conversione precedente, è possibile usare gli oggetti intrinseci hardware specifici della piattaforma. Ad esempio, si può usare Sse.ConvertToInt32(Vector128.CreateScalar(val)) per gestire (int)val
per float
. È necessario verificare if (Sse.IsSupported)
prima dell'uso. L'uso di questi oggetti intrinseci è difficile, però, perché altre piattaforme di destinazione (ad esempio Arm64) già producono già diversi.
API interessate
Tutti i cast espliciti e impliciti dal virgola mobile a integer:
(int)val
doveval
è unfloat
odouble
Vector.ConvertToInt32(Vector<float> val)
(long)val
doveval
è unfloat
odouble
Vector.ConvertToInt64(Vector<double> val)
(uint)val
doveval
è unfloat
odouble
Vector.ConvertToUInt32(Vector<float> val)
(ulong)val
doveval
è unfloat
odouble
Vector.ConvertToUInt64(Vector<double> val)