在哪个平台上整数除以零触发浮点异常? [英] On which platforms does integer divide by zero trigger a floating point exception?

查看:408
本文介绍了在哪个平台上整数除以零触发浮点异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在另一个问题中,有人正在想知道为什么他们得到一个浮点错误,实际上他们的C ++程序中有一个除数为零的整数。一个讨论是围绕着这一点出发的,有些人认为浮点异常实际上从来没有提出,因为 float 除以零,但是仅在整数除以零。



这听起来很奇怪,因为我知道:


  1. MSVC-所有Windows平台上的x86和x64上的编译代码报告一个int除以零为0xc0000094:整数除以零,浮点除以零为0xC000008E浮点除以零(启用时)


  2. IA-32和AMD64 /x86/DIV.htmlrel =nofollow noreferrer> #DE (整数除法异常)作为中断0.浮点异常触发中断16( x87浮点数)或中断19(SIMD浮点p oint)


  3. 其他硬件具有类似的不同中断(例如, PPC在float-div-by-zero上增加0x7000, t / p>


  4. 我们的应用程序使用 _controlfp_s取消屏蔽浮点异常内在(最终 stmxcsr op),然后捕获它们进行调试。所以我确实在实践中看到了IEEE754除以零的例外。


所以我得出结论,有一些平台它将int异常报告为浮点异常,例如 x64 Linux(无论ALU管道如何,都提高所有算术错误的SIGFPE)



什么其他操作系统(或C / C ++运行时,如果您是操作系统)报告整数div-by-zero作为浮点数例外?

解决方案

我不知道目前的情况如何,但目前情况是FP异常检测支持与整数非常不同。整数除法陷阱是很常见的。 POSIX要求它提高 SIGFPE ,如果它引发了一个异常。



但是,您可以整理出什么样的SIGFPE,看到它实际上是一个除法例外。 (不一定除以零,但是:2的补码 INT_MIN / -1 分区陷阱和 x86的 div idiv 也陷阱,64b / 32b分区的商不符合32b输出寄存器。)



glibc手册解释 BSD和GNU系统提供了一个额外的参数信号处理程序为 SIGFPE ,它将为 FPE_INTDIV_TRAP 除以零。 POSIX文件 FPE_INTDIV_TRAP 作为 siginfo_t int si_code 字段,在 siginfo_t 包含该成员的系统上。



如果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



甚至允许这样的事情在异常被屏蔽时产生明智的结果:

  double x = 0.0; 
double y = 1.0 / x; // y = + Inf
double z = 1.0 / y; // z = 1 / Inf = 0.0,无FP异常






FP与整数错误检测

检测错误的FP方法是非常好的:当异常被屏蔽时,它们在FP状态寄存器中设置一个标志,而不是诱捕。 (例如x86的MXCSR用于SSE指令)。标志保持设置,直到手动清除,因此您可以检查一次(例如循环后)以查看发生的异常,但不发生哪些异常。



具有类似粘性整数溢出标记的提案以记录在计算序列期间的任何点是否发生溢出。允许整数除法被屏蔽在某些情况下会很好,但在其他情况下是危险的(例如在地址计算中,你应该陷阱而不是潜在的存储到一个虚假的位置)。



然而,在x86上,检测在计算序列中是否发生整数溢出时,需要在每一个之后放置条件分支,因为标志只是被覆盖。 MIPS有一个 add 指令,它将陷入带符号溢出,以及一个从未陷入的无符号指令。因此,整数异常检测和处理标准化程度要少得多。






整数除法无法生成NaN或inf结果,所以它是有道理的这种方式



整数除法产生的任何整数位模式都是错误的,因为它将表示一个特定的有限值。



但是,在x86上,将超出范围的浮点值转换为整数,并使用 cvtsd2si 或任何类似的转换指令产生整数不确定值,如果浮点无效异常被屏蔽。除了符号位之外,该值为全零。即 INT_MIN



(请参阅英特尔手册, x86 tag wiki。


In another question, someone was wondering why they were getting a "floating point error" when in fact they had an integer divide-by-zero in their C++ program. A discussion arose around this, with some asserting that floating point exceptions are in fact never raised for float divide by zero, but only arise on integer divide by zero.

This sounds strange to me, because I know that:

  1. MSVC-compiled code on x86 and x64 on all Windows platforms reports an int divide by zero as "0xc0000094: Integer division by zero", and float divide by zero as 0xC000008E "Floating-point division by zero" (when enabled)

  2. IA-32 and AMD64 ISAs specify #DE (integer divide exception) as interrupt 0. Floating-point exceptions trigger interrupt 16 (x87 floating-point) or interrupt 19 (SIMD floating-point).

  3. Other hardware have similarly different interrupts (eg PPC raises 0x7000 on float-div-by-zero and doesn't trap for int/0 at all).

  4. 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.

So I conclude that there are some platforms that report int exceptions as floating point exceptions, such as x64 Linux (raising SIGFPE for all arithmetic errors regardless of ALU pipe).

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'm not sure how the current situation came to be, but it's currently the case that FP exception detection support is very different from integer. It's common for integer division to trap. POSIX requires it to raise SIGFPE if it raises an exception at all.

However, you can sort out what kind of SIGFPE it was, to see that it was actually a division exception. (Not necessarily divide-by-zero, though: 2's complement INT_MIN / -1 division traps, and x86's div and idiv also trap when the quotient of 64b/32b division doesn't fit in the 32b output register.)

The glibc manual explains that BSD and GNU systems deliver an extra arg to the signal handler for SIGFPE, which will be FPE_INTDIV_TRAP for divide by zero. POSIX documents FPE_INTDIV_TRAP as a possible value for siginfo_t's int si_code field, on systems where siginfo_t includes that member.

IDK if Windows delivers a different exception in the first place, or if it bundles things into different flavours of the same arithmetic exception like Unix does. If so, the default handler decodes the extra info to tell you what kind of exception it was.

POSIX and Windows both use the phrase "division by zero" to cover all integer division exceptions, so apparently this is common shorthand. For people that do know about about INT_MIN / -1 (with 2's complement) being a problem, the phrase "division by zero" can be taken as synonymous with a divide exception. The phrase immediately points out the common case for people that don't know why integer division might be a problem.


FP exceptions semantics

FP exceptions are masked by default for user-space processes in most operating systems / C ABIs.

This makes sense, because IEEE floating point can represent infinities, and has NaN to propagate the error to all future calculations using the value.

  • 0.0/0.0 => NaN
  • If x is finite: x/0.0 => +/-Inf with the sign of x

This even allows things like this to produce a sensible result when exceptions are masked:

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 vs. integer error detection

The FP way of detecting errors is pretty good: when exceptions are masked, they set a flag in the FP status register instead of trapping. (e.g. x86's MXCSR for SSE instructions). The flag stays set until manually cleared, so you can check once (after a loop for example) to see which exceptions happened, but not where they happened.

There have been proposals for having similar "sticky" integer-overflow flags to record if overflow happened at any point during a sequence of computations. Allowing integer division exceptions to be masked would be nice in some cases, but dangerous in other cases (e.g. in an address calculation, you should trap instead of potentially storing to a bogus location).

On x86, though, detecting if integer overflow happened during a sequence of calculations requires putting a conditional branch after every one of them, because flags are just overwritten. MIPS has an add instruction that will trap on signed overflow, and an unsigned instruction that never traps. So integer exception detection and handling is a lot less standardized.


Integer division doesn't have the option of producing NaN or Inf results, so it makes sense for it to work this way.

Any integer bit pattern produced by integer division will be wrong, because it will represent a specific finite value.

However, on x86, converting an out-of-range floating point value to integer with cvtsd2si or any similar conversion instruction produces the "integer indefinite" value if the "floating-point invalid" exception is masked. The value is all-zero except the sign bit. i.e. INT_MIN.

(See the Intel manuals, links in the tag wiki.

这篇关于在哪个平台上整数除以零触发浮点异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆