On which platforms does integer divide by zero trigger a floating point exception?
在另一个问题中,有人想知道他们为什么会得到一个"浮点错误",实际上他们的C ++程序中有一个整数除零。围绕这一点进行了讨论,有些人声称浮点异常实际上从未因浮点除以零而增加,而只是在整数除以零时出现。
这听起来很奇怪,因为我知道:
所有Windows平台上x86和x64上的MSVC编译代码报告int除以零为"0xc0000094:整数除以零",浮点除以零为0xC000008E"浮点除以零"(启用时)
IA-32和AMD64 ISA将
其他硬件具有类似的不同中断(例如,PPC在float-div-by上引发0x7000并且根本不捕获int / 0)。
我们的应用程序使用
因此,我得出结论,有些平台将异常作为浮点异常报告,例如x64 Linux(无论ALU管道如何,都会针对所有算术错误提升SIGFPE)。
其他操作系统(如果您是操作系统,还是C / C ++运行时)报告整数除零作为浮点异常?
我不确定目前的情况如何,但目前的情况是FP异常检测支持与整数非常不同。陷阱的整数除法很常见。 POSIX要求它提升
但是,你可以理清它是什么类型的SIGFPE,看它实际上是一个除法异常。 (但不一定是除以0:2的补码
glibc手册解释了BSD和GNU系统为
IDK,如果Windows首先提供不同的异常,或者它将事物捆绑到与Unix相同的算术异常的不同风格中。如果是这样,默认处理程序会对额外信息进行解码,以告诉您它是什么类型的异常。
POSIX和Windows都使用短语"除以零"来涵盖所有整数除法异常,所以显然这是常见的简写。对于知道关于INT_MIN / -1(带有2的补码)的人来说是一个问题,短语"除以零"可以被视为除法异常的同义词。这句话立即指出了那些不知道为什么整数除法可能成为问题的人的常见情况。
FP异常语义
对于大多数操作系统/ C ABI中的用户空间进程,FP异常在默认情况下被屏蔽。
这是有道理的,因为IEEE浮点可以表示无穷大,并且有NaN将错误传播到使用该值的所有未来计算。
-
0.0/0.0 =>NaN -
如果
x 是有限的:x/0.0 =>+/-Inf ,符号为x
这甚至允许这样的事情在掩盖异常时产生合理的结果:
1 2 3 | double x = 0.0; double y = 1.0/x; // y = +Inf double z = 1.0/y; // z = 1/Inf = 0.0, no FP exception |
FP与整数错误检测
FP检测错误的方法非常好:当屏蔽异常时,它们在FP状态寄存器中设置一个标志而不是陷阱。 (例如x86的MXCSR用于SSE指令)。标志保持设置直到手动清除,因此您可以检查一次(例如循环之后)以查看发生了哪些异常,但不是它们发生的位置。
已经提出了具有类似"粘性"整数溢出标志的建议,以记录在计算序列期间的任何点处是否发生溢出。允许屏蔽整数除法异常在某些情况下会很好,但在其他情况下会很危险(例如在地址计算中,您应该捕获而不是潜在地存储到虚假位置)。
但是,在x86上,检测在计算序列期间是否发生整数溢出需要在每一个之后放置一个条件分支,因为标志只是被覆盖。 MIPS有一条
整数除法不能选择产生NaN或Inf结果,因此以这种方式工作是有意义的。
整数除法产生的任何整数位模式都是错误的,因为它将代表一个特定的有限值。
但是,在x86上,如果屏蔽了"浮点无效"异常,则将超出范围的浮点值转换为带有
(参见英特尔手册,x86标签wiki中的链接。
What other operating systems (or C/C++ runtimes if you are the operating system) report integer div-by-zero as a floating point exception?
答案取决于您是在内核空间还是用户空间。 如果你在内核空间,可以将"i / 0"放在
AMD64 hardware specifies integer divide by zero as interrupt 0, different from interrupt 16 (x87 floating-point exception) and interrupt 19 (SIMD floating-point exception).
"除零"异常是用
Other hardware have similarly different interrupts (eg PPC raises 0x7000 on float-div-by-zero and doesn't trap for int/0 at all).
更具体地说,
另一方面,整数除法是每个PPC PEM的未定义行为:
8-53 divw
If an attempt is made to perform either of the divisions—0x8000_0000 ÷
–1 or ÷ 0, then the contents of rD are undefined, as are
the contents of the LT, GT, and EQ bits of the CR0 field (if Rc = 1).
In this case, if OE = 1 then OV is set.
Our application unmasks floating-point exceptions for divide-by-zero with the
_controlfp_s intrinsic (ultimately stmxcsr op) and then catches them for debugging purposes. So I have definitely seen IEEE754 divide-by-zero exceptions in practice.
我认为你的时间最好花在编译时而不是在运行时除以零。
对于用户空间,这发生在运行在POWER上的AIX上,在PA-RISC上运行的HP-UX,在x86-64上运行的Linux,在x86-64上运行的macOS,在Alpha上运行的Tru64和在SPARC上运行的Solaris上。
在编译时避免除零会好得多。