浮点数到整数转换将要饱和
现在,浮点数到整数转换在 x86 和 x64 计算机上具有饱和行为。 饱和行为意味着,如果转换后的值对于目标类型来说太小或太大,则该值分别设置为该类型的最小值或最大值。
旧行为
下表显示了转换 float
或 double
值时的以前行为。
转换为... | x 的值 |
(上一个)结果 |
---|---|---|
int 标量和打包 |
int.MinValue <= x <= int.MaxValue |
(int)x |
< int.MinValue 或 > int.MaxValue |
int.MinValue |
|
long 标量和打包 |
long.MinValue <= x <= long.MaxValue |
(long)x |
< long.MinValue 或 > long.MaxValue |
long.MinValue |
|
uint 标量和打包 |
任何值 | (((long)x << 32) >> 32) |
ulong 标量和打包 |
<= 2^63 |
(long)x |
> 2^63 |
(long)(x - 2^63) + 2^63 |
新行为
下表显示了转换 float
或 double
值时的新行为。
转换为... | x 的值 |
.NET 9+ 结果 |
---|---|---|
int 标量和打包 |
int.MinValue <= x <= int.MaxValue |
(int)x |
< int.MinValue |
int.MinValue |
|
> int.MaxValue |
int.MaxValue |
|
NaN |
0 | |
long 标量和打包 |
long.MinValue <= x <= long.MaxValue |
(long)x |
< long.MinValue |
long.MinValue |
|
> long.MaxValue |
long.MaxValue |
|
NaN |
0 | |
uint 标量和打包 |
0 <= x <= uint.MaxValue |
(uint)x |
x > uint.MaxValue |
uint.MaxValue |
|
x < 0 |
0 | |
ulong 标量和打包 |
0 <= x <= ulong.MaxValue |
(ulong)x |
x > ulong.MaxValue |
ulong.MaxValue |
|
x < 0 |
0 |
引入的版本
.NET 9 预览版 4
中断性变更的类型
此更改为行为更改。
更改原因
此更改旨在标准化所有浮点数到整数的转换,使其具有饱和行为,并使行为具有确定性。
建议的操作
如果你依赖以前的行为部分中所显示并且要从转换中返回的值,那么即使这些值不正确,也要更新代码以获取新行为部分中显示的值。
如果方案不需要新行为的性能开销,则可以对单精度、双精度和半精度改用新 ConvertToIntegerNative<TInteger>
方法。 在大多数情况下,这些方法的行为与以前的浮点数到整数转换行为匹配。 但是,这些方法具有平台特定的行为,不能保证此行为与以前的转换行为(已经具有非确定性)匹配。 相反,这些方法会对本机平台执行最高效的操作。 值得注意的是,对于超出 TInteger
类型的可表示范围的值,不能保证结果。
在需要性能并严格保证匹配以前的转换行为的特殊情况下,你可以使用特定于平台的硬件内部函数。 例如,你可以使用 Sse.ConvertToInt32(Vector128.CreateScalar(val)) 处理 float
的 (int)val
。 在使用之前,你必须检查 if (Sse.IsSupported)
。 但是,使用这些内部函数很棘手,因为其他目标平台(如 Arm64)已经产生了不同的结果。
受影响的 API
从浮点数到整数的所有显式和隐式转换:
(int)val
,其中val
是float
或double
。Vector.ConvertToInt32(Vector<float> val)
(long)val
,其中val
是float
或double
。Vector.ConvertToInt64(Vector<double> val)
(uint)val
,其中val
是float
或double
。Vector.ConvertToUInt32(Vector<float> val)
(ulong)val
,其中val
是float
或double
。Vector.ConvertToUInt64(Vector<double> val)