AVX指令集中的32种浮点比较关系详解

        在传统印象中,数字的比较关系只有6种。但在AVX指令集中,Intel一下给出了32种浮点比较谓词,详见下图--

(Intel手册:Table 3-9. Comparison Predicate for VCMPPD and VCMPPS Instructions)
  为什么会有这么多种比较谓词呢?我为此困惑困惑了很久。
  直到最近翻阅了不少资料后,才终于将它们弄懂了。
一、浮点数据类型
  Intel使用的是IEEE 754规范的浮点数据类型。对于浮点数据类型来说,除了可以存储数字、无穷之外,还可以存储 NaN(not a number。非数)。
  NaN(非数)分为两大类--
1. QNaN:quiet NaN,静默非数。当禁止异常时,若浮点运算无效(例如 “零除以零”、“对负数开方”等),就返回QNaN表示运算无效。
2. SNaN:signaling NaN,信号非数。当浮点运算遇到SNaN时,会立即抛出异常。例如可以用来检查变量是否被初始化(定义变量时设为SNaN,如果用户没有将它初始化就调用浮点运算,会抛出异常)。
  在Intel手册上有张浮点数编码表,位于“Volume 1: Basic Architecture ”\“Chapter 4 Data Types”\“4.2 Numeric Data Types”\“4.2.2 Floating-Point Data Types”--

(Intel手册:Table 4-3. Floating-Point Number and NaN Encodings)
  从上表中可以得知--
1.NaN的阶码为全1,符号位被忽略。通过尾数来判断是SNaN或QNaN。
2.SNaN的尾数的最高为0,其他位非0。
3.QNaN的尾数的最高为1,其他位非0。
4.还存在一个特殊的QNaN--QNaN Floating-Point Indefinite:表示“不确定浮点值”的静默非数。可参考周明德《64位微处理器应用编程》“5.4.4数的编码”中“3、不确定值”。
  关于NaN的运算细节,可参考Intel手册中“4.8.3.4 NaNs”至“4.8.3.7 QNaN Floating-Point Indefinite”的内容。
二、两种特殊的比较关系--“无序”、“有序”
  传统的数字的比较关系是这6种--
1.等于(Equal)。谓词缩写为“EQ”。C语言运算符为“==”。
2.小于(Less than)。谓词缩写为“LT”。C语言运算符为“<”。
3.小于等于(Less than or equal)。谓词缩写为“LE”。C语言运算符为“<=”。
4.大于(Greater than)。谓词缩写为“GT”。C语言运算符为“>”。
5.大于等于(Greater than or equal)。谓词缩写为“GE”。C语言运算符为“>=”。
6.不等于(Not equal)。谓词缩写为“NEQ”。C语言运算符为“!=”。
  一般来说,上面的6种比较关系只对数字(包括无穷大)有效。即两边的操作数都必须是数字,任何一个都不能为NaN。
  若任一操作数是NaN(非数),那么将无法进行比较,前5种比较关系都返回False。包括“NaN==NaN”的返回值都是False。
  而“不等于”就有点微妙,因为它是“等于”的相反值。所以当任一操作数是NaN时,“不等于”也返回True。因此,将它称为“ 不等于或无序”将会更好。
  “无序”是专门为NaN而设计的比较关系,既然有了“无序”,那么也可以定义一个跟它效果相反的运算符“有序”,它们详细定义如下--
无序(Unordered。当至少一个操作数是NaN时,返回True。若操作数都不是NaN时,返回False。谓词缩写为“UNORD”。一般借用符号“?”表示“无序”关系。
有序(Ordered。当操作数都不是Nan时,返回True。若至少一个操作数是NaN时,返回False。谓词缩写为“ORD”。一般借用符号“!?”表示“有序”关系。
  可这样理解--
有序:能比较大小。
无序:不能比较大小。
三、SIMD(SSE/AVX)中的NaN与异常
  在使用AVX指令集时,依然是靠MXCSR寄存器来控制浮点运算的。在Intel手册“10.2.3 MXCSR Control and Status Register”中有该寄存器的详细定义--(Intel手册:Figure 10-3. MXCSR Control/Status Register)
  当CPU发现浮点运算无效时--
1. 首先将MXCSR寄存器的最低位(IE:Invalid Operation Flag)设为1。
2. 随后CPU检查MXCSR寄存器的第7位(IM:Invalid Operation Mask),若IM为1(masked,屏蔽),就返回QNaN(或特殊值);若IM为0(unmasked,非屏蔽),就触发#IA异常。
注:#IA是无效算术操作异常,详见Intel手册“8.5.1.2 Invalid Arithmetic Operand Exception (#IA)”。
  一般来说,等于、小于等比较操作遇到NaN时会引发上述流程--
1.将IE设为1。
2.若IM为1,不会触发异常,返回比较结果;若IM为0,会触发异常。
  而对于“无序”比较来说,因为它本来就是用来检查NaN,不希望触发异常。所以CPU对这一类操作做了特殊处理,不会执行上述操作。

  即浮点比较会因是否抛出异常而分为两类--
1.signaling(发信号):遇到NaN时,设置IE,根据IM决定是返回比较结果,还是抛出异常。
2.non-signaling(不发信号): 遇到NaN时,总是返回比较结果,从不抛出异常。
四、32种浮点比较关系详解
  学习了上面那些知识点后,现在可以读懂AVX指令集中的32种浮点比较关系了。

Predicate:比较谓词。
imm8 Value:8位立即数。
Description:描述。
Result: A Is 1st Operand, B Is 2nd Operand:返回值:A是第一个操作数,B是第二个操作数。
A > B:大于。
A < B:小于。
A = B:等于。
Unordered:无序。
Signals #IA on QNAN:当遇到QNaN时是否发信号#IA。
注:较复杂的比较关系可以由“大于”、“小于”、“等于”、“无序”这四种基本关系所组成。例如“小于等于”由“小于”、“等于”组成。
  我将该表格翻译了一下,并增加了符号形式描述--

谓词:比较谓词。
imm8:8位立即数。
符:符号形式描述。
描述:文字形式描述。
符2:另一种符号形式描述。
描述2:另一种文字形式描述。
A > B:大于。
A < B:小于。
A = B:等于。
无序:无序。
#IA:Signals #IA on QNAN。
  观察这张表格,会发现谓词的命名是有规则的,它由三部分组成,格式大致为“①_②③”,含义如下--
①.下划线前的是第一部分,它是谓词缩写,用于描述功能。例如“EQ_OQ”中的“EQ”代表“等于”。
②.在下划线与最后字母之间的是第二部分,只能是O、U或忽略。O代表有序,U代表无序。
③.最后的那个字母是第三部分,只能是Q或S,分别代表non-signaling和signaling。例如“EQ_OQ”中的“Q”代表“non-signaling”。该字母其实代表的是#IA这一列,为“Q”时“#IA”列为“No”,为“S”时“#IA”列为“Yes”。
  AVX指令集中的VCMPPS等比较指令是继承自SSE指令集中的CMPPS等指令的,它们靠一个8位立即数(imm8)来区分比较谓词。
  SSE指令集只定义了前8种比较谓词,所以imm8只有最低3位有效。上表“谓词”后面括号内的就是SSE时代的谓词名称。
  AVX指令集将其扩展到32种比较谓词,所以imm8只有最低5位有效。

  Intel在设计AVX指令集的比较谓词时,先根据无序、有序和FALSE、TRUE,将比较谓词扩充到16种。然后再反转non-signaling/signaling,又定义了16种比较谓词。合计32种比较谓词。

原文转载自https://software.intel.com/zh-cn/node/170638

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值