x86|VS2022和浮点整型转换

x86|VS2022和浮点整型转换

文章图片


先快速总结下今天的内容:
> 不再支持/QIfirst 。
> MSVC现在可以兼容标准C++中的所有浮点整型转换 。
> 浮点转换为带符号的整型数未发生改变 。
> 在默认情况下 , 对于浮点整型转换 , VS2022保持与VS2017及其更早版本的兼容性 。
> 对于VS2019中的浮点转换为无符号整型 , 有如下几点说明
>> 当面向x64时 , 它通常会和VS2017兼容 。
>> 当面向x86时 , 它通常会和AVX-512兼容 。
>> 对于v16.7及更高版本 , 可以使用/fpcvt:BC编译开关以和VS2017保持兼容性 。
> 编译器内部函数(Intrinsic Functions)可以提供更多选项及更精细化的控制 。
简介你可能已经知道了 , VS2019更改了英特尔架构 (IA) 的一些浮点到整型转换 。 当面向32位的IA(x86)架构是 , 大多数转换与英特尔 AVX-512 转换指令相匹配 。对于有符号整数 , 这与VS2017 相同 。 对于无符号整数 , 无效转换的结果可能不同 , 我会在后面进行解释 。对于 64 位 IA (x64) , 当选择 /arch:AVX512 时 , 会使用 AVX-512 指令 , 但其他方面与 VS2017 没有变化 。 很抱歉 , 我们没有宣布这一变化 , 直到 16.7 版本我们才提供向后兼容的选项 。
默认情况下 , VS2022恢复为VS2017后会处理这些转换 。它还保留了使用与 AVX-512 兼容的转换的选项 。这篇文章会告诉你更多相关信息 , 包括你可能想要使用的其他选项 。
背景知识标准C++指定了对数据进行有效转换的工作方式 , 但无效转换可以做任何事情 。 有效的转换从截断浮点值开始 , 它丢弃任何小数部分 , 只留下整数值 。 这也称为“向零舍入” 。 如果截断的值可以用结果类型表示 , 则转换有效 , 并且结果必须是该值 。
十多年来 , MSVC 一直与此方式兼容 , 并且直到符号类型的无效转换才发生了变化 。 大多数浮点运算通过返回特殊的“非数字”(NaN) 值来指示无效运算 , 但转换为整数不允许该选项 。 任何结果值都可以来自有效的转换 , 并且无效转换没有单一的“正确”结果 。
当然 , 这种完全随机的转换结果 , 是没有用的 , 所以通常使用两种不同的方法 。 英特尔架构 (IA) 使用离零最远的结果值代替 NaN , 因此任何无效的转换都会返回此标记值 。(返回的具体值取决于结果类型 。 ) 临界值易于测试 , 并且在测试和调试过程中经常会导致独特的行为 。
【x86|VS2022和浮点整型转换】另一种常见的方法称为饱和 , 其中任何太高而无法放入目标类型的浮点值 , 它都会给出可能的最高目标值 , 而任何太低而无法容纳的值 , 它都会给出可能的最低值 。 如果原值为 NaN , 则结果将返回零 。 即使结果是错误的 , 也尽可能接近正确的结果 , 可能不太可能导致失败 。ARM 对其转换指令使用饱和的方式 。
VS2017中的转换规则自第一台 IBM PC 出现之前 , 英特尔架构就有将浮点类型转换为有符号整数类型的指令 , 但在 AVX-512 中首次引入了转换为无符号整数类型的指令 。在VS2017 之前 , 到无符号整数类型的转换基于到 long long 类型的转换 。转换为 unsigned 首先转换为 long long , 然后截断为 32 位 。转换为 unsigned long long 时 , 对于 long long 来说太高的有效源值将作为特殊情况处理 。所有其他值都简单地转换为 long long 并重新转换 。这解决了缺少无符号转换指令的问题 , 但为无效转换返回的值并不是特别有用 。