这个问题从出现为什么isnormal()说的值是正常的,当它是不是?
AC编译器生成以下代码这是为了检测该32位float
传递在正常与否:
flds 24(%esp)
fxam; fstsw %ax;
andw $17664, %ax
cmpw $1024, %ax
sete %al
(完整的代码可以看到这里 )。
这是代码是否正确? 该程序似乎不正确的行为,说一个数字是正常时,它不是。 我们认为,也许正在检查的数量为双精度常态这里。
我检查了英特尔的insn的参考手册 ,从链接https://stackoverflow.com/tags/x86/info 。
只有一个版本的fxam
指令,它在80bit的寄存器进行操作。 所以,是的,那(低效率)测试80bit的临时常态。 (更高效的将是test $1024, %eax
,而不是掩盖,然后cmp
)。
根据这个 , flds
本身将引发一个非规格化异常。 我想,这意味着它测试的实际源,转换为80bit的没有结果。 该页面表示,非正规异常将在状态字的位。
英特尔的参考手册没有说任何事情fld
设置状态字,只是设置C1标志,并留下C0东西,C2和C3未定义。 它说,你可以得到一个#D FPU异常,如果来源是反规范,但如果来源是80bit的格式,这种情况不会发生。
我不知道,如果状态字会真正得到设置非规格化如果未启用FPU异常。 我不是这方面的专家。 我的阅读此页 (和控制字节)是FPU状态字大部分指令后更新。 如果D
位在控制寄存器中设置(它是通过缺省值),则操作数反规范设定的D
状态字位。 这是未设置(揭露),异常会发生。
所以我觉得一个函数来测试一个浮动的非正规会是什么样子:
isdenormalf:
flds (%rdi) # sets FPU status based on the input to the 32->80bit conversion
fstsw %ax
fstp %st0 # pop
test $2, %al # avoid 16 bit ops (%ax), they're slow on Intel
sete %al # or just branch on flags directly if your compiler's smart
ret
我没有试过,所以它可能是完全伪造的。 在弹出的是我们要保持负载可能是不平凡的内联数据空载/的方式写的。 也许需要一个地址精氨酸,返回浮点(因此它可以在的x87寄存器),和具有与所述状况的输出ARG。
我没有看到,可以检查的指令float
在SSE寄存器非标准。
我想我有一个(慢)的方式来测试与SSE4.1或AVX的非正规数ROUNDSS
。 您需要根据输入的符号使用不同的版本。
对于正值:
- 对回合
+inf
与非正规数为零 - 圆往
+inf
没有非正规数为零。 - 如果两个舍入结果是不同的,那么非正规数为零了影响(这意味着输入是反规范)
负数需要对要舍-inf
,不+inf
,否则-0.xx
将始终向零。 因此,这将有一个分支,二ROUNDSS
ES和比较。 在IEEE浮点格式位黑客可能会更快。