关于Integer Overflow异常

时间:2021-03-01 21:26:17
在汇编语言编程中出现的问题,在WIN32下编写如下代码:

#include <iostream>
#include "windows.h"

using namespace std;

int main()
{
__try
{
// edx : eax = 0x2000000000
// (edx : eax) / 1 = 0x2000000000 > 0x100000000
__asm
{
mov edx, 0x20
mov ecx, 1
idiv ecx
}
cout << "Not Overflow\n";
}
__except (GetExceptionCode() == EXCEPTION_INT_OVERFLOW)
{
cout << "Integer Overflow\n";
}
cin.get();
return 0;
}

运行结果
Integer Overflow

原因应该是明显的吧,idiv指令运算的结果无法容纳在一个32位寄存器里,所以抛出了溢出异常
我想问一下有没有办法能让windows不去检测idiv的结果的溢出情况(我的代码中会自行处理),不要抛出异常
说明一下:尽管可以每次都忽略异常并让程序继续运行,不过这个除法嵌套在一个反复执行的循环中(1千万次以上),效率很重要,所以每次让操作系统抛出异常,然后再在异常处理中去处理的效率很低下,有没有办法直接让windows不去进行检测溢出

21 个解决方案

#1


引用楼主 lacs34 的回复:
在汇编语言编程中出现的问题,在WIN32下编写如下代码:

C/C++ code

#include <iostream>
#include "windows.h"

using namespace std;

int main()
{
    __try
    {
        // edx : eax = 0x2000000000
        // (edx……

为什么不研究用循环指令啊?

#2


这个异常,不是 Windows 检测或触发的吧,而是由 cpu 的执行机构抛出,被 Windows 的异常例程接管进行处理而已。资料上说,除0 异常不能被禁止。

#3


你是指用循环指令模拟除法指令?
那样不是会慢好多么?

#4


引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

#5


引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

当然用循环做除法对结果有点偏差。

#6


引用 2 楼 zara 的回复:
这个异常,不是 Windows 检测或触发的吧,而是由 cpu 的执行机构抛出,被 Windows 的异常例程接管进行处理而已。资料上说,除0 异常不能被禁止。

这里是只是溢出而已,不是除0异常

#7


引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

64位数除32位数的除法的软实现比硬实现快?

#8


引用 6 楼 lacs34 的回复:
这里是只是溢出而已,不是除0异常

都是一样的。看 div 指令的说明里,#DE 发生的情况,1. 是除数为 0 ,2. 是商太大,寄存器放不下。

除非的除数比较特异,比如是 1/2/4 之类的,可用简单地通过一两个移位指令实现,否则只是个普通数值又无甚规律的话,移位操作不会比除法指令更具优势。毕竟,现在的 cpu 对 div r32 类指令,也就几个 uop 而已。

#9


引用 7 楼 lacs34 的回复:
引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

64位数除32位数的除法的软实现比硬实现快?

关于快慢问题你可以查指令手册,不多说。
我发现,你是不是程序写错了,0x2000000000没有超过32位啊,你应该将它放在EAX中,然后扩展一下EAX,再做有符号除法啊。

#10


引用 8 楼 zara 的回复:
引用 6 楼 lacs34 的回复:这里是只是溢出而已,不是除0异常
都是一样的。看 div 指令的说明里,#DE 发生的情况,1. 是除数为 0 ,2. 是商太大,寄存器放不下。

除非的除数比较特异,比如是 1/2/4 之类的,可用简单地通过一两个移位指令实现,否则只是个普通数值又无甚规律的话,移位操作不会比除法指令更具优势。毕竟,现在的 cpu 对 div r32 类指令,也就几个 u……

对不起,我看错位数了

#11


引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

你们所说的指令手册是指《Intel® 64 and IA-32 Architectures Software Developer’s Manual》吗,我看了下idiv指令部分没有关于指令执行速度的说明?

#12


引用 11 楼 lacs34 的回复:
引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

你们所说的指令手册是指《Intel® 64 and IA-32 Architectures Software Developer’s Manual》……

新的我也没找到,这里有一个还可以参考一下
http://bbs.chinaunix.net/thread-2133668-1-1.html

#13


引用 7 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?
正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。
64位数除32位数的除法的软实现比硬实现快?

你说的还是有一定道理的,老机器的处理器乘除法占时是比较长,后来硬件速度的确提高不少。

#14


指令时序表,最新的到 2011-06-08,可用在  http://www.agner.org/optimize/ 4. 里下载到;或者直接  http://www.agner.org/optimize/instruction_tables.pdf

#15


http://bbs.chinaunix.net/thread-2133668-1-1.html
上面的参考资料看了,一条除法指令才46个时钟周期,请问一下用什么算法能超过这个速度?
用模拟硬件除法的方法来写除法平均计算每一位两条指令好像不够...

#16


引用 11 楼 lacs34 的回复:
引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

你们所说的指令手册是指《Intel® 64 and IA-32 Architectures Software Developer’s Manual》……

我做了个程序看了一下,用.lst 列表看了一下,在我的机子上
 0010   2   -- -- shr ax,1
 0012   2   -- -- rol ax,1
 0014 113+  -- -- idiv table

idiv 113+ ,加两个只有2

#17


咦,哪个汇编器能给出这个信息,好像还是基于 8086 的?看上面提及的那个手册里,45nm 制程的 Core2 象 div/idiv 这样的指令,除数是寄存器的话,16/32 的是 7 个微时序,8 位的才 4 个。其它的普通算术运算指令,对寄存器的操作,一般也需要 1-2 个时序的。
还真不能拿上古时代的资料来衡量当下的配置的。

#18


可以改成浮点除法运算,或者用SSE除法指令。

#19


据我所知,SSE好像没有除法指令。不过,如果除数是一个固定的数。可以采用以乘代除法,速度比直接使用除法快上很多。

#20


divss、divsd、divps、divpd

#21


sorry, 我没说清楚,我指的是SSE指令中没有整数除法指令。

#1


引用楼主 lacs34 的回复:
在汇编语言编程中出现的问题,在WIN32下编写如下代码:

C/C++ code

#include <iostream>
#include "windows.h"

using namespace std;

int main()
{
    __try
    {
        // edx : eax = 0x2000000000
        // (edx……

为什么不研究用循环指令啊?

#2


这个异常,不是 Windows 检测或触发的吧,而是由 cpu 的执行机构抛出,被 Windows 的异常例程接管进行处理而已。资料上说,除0 异常不能被禁止。

#3


你是指用循环指令模拟除法指令?
那样不是会慢好多么?

#4


引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

#5


引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

当然用循环做除法对结果有点偏差。

#6


引用 2 楼 zara 的回复:
这个异常,不是 Windows 检测或触发的吧,而是由 cpu 的执行机构抛出,被 Windows 的异常例程接管进行处理而已。资料上说,除0 异常不能被禁止。

这里是只是溢出而已,不是除0异常

#7


引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

64位数除32位数的除法的软实现比硬实现快?

#8


引用 6 楼 lacs34 的回复:
这里是只是溢出而已,不是除0异常

都是一样的。看 div 指令的说明里,#DE 发生的情况,1. 是除数为 0 ,2. 是商太大,寄存器放不下。

除非的除数比较特异,比如是 1/2/4 之类的,可用简单地通过一两个移位指令实现,否则只是个普通数值又无甚规律的话,移位操作不会比除法指令更具优势。毕竟,现在的 cpu 对 div r32 类指令,也就几个 uop 而已。

#9


引用 7 楼 lacs34 的回复:
引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

64位数除32位数的除法的软实现比硬实现快?

关于快慢问题你可以查指令手册,不多说。
我发现,你是不是程序写错了,0x2000000000没有超过32位啊,你应该将它放在EAX中,然后扩展一下EAX,再做有符号除法啊。

#10


引用 8 楼 zara 的回复:
引用 6 楼 lacs34 的回复:这里是只是溢出而已,不是除0异常
都是一样的。看 div 指令的说明里,#DE 发生的情况,1. 是除数为 0 ,2. 是商太大,寄存器放不下。

除非的除数比较特异,比如是 1/2/4 之类的,可用简单地通过一两个移位指令实现,否则只是个普通数值又无甚规律的话,移位操作不会比除法指令更具优势。毕竟,现在的 cpu 对 div r32 类指令,也就几个 u……

对不起,我看错位数了

#11


引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

你们所说的指令手册是指《Intel® 64 and IA-32 Architectures Software Developer’s Manual》吗,我看了下idiv指令部分没有关于指令执行速度的说明?

#12


引用 11 楼 lacs34 的回复:
引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

你们所说的指令手册是指《Intel® 64 and IA-32 Architectures Software Developer’s Manual》……

新的我也没找到,这里有一个还可以参考一下
http://bbs.chinaunix.net/thread-2133668-1-1.html

#13


引用 7 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?
正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。
64位数除32位数的除法的软实现比硬实现快?

你说的还是有一定道理的,老机器的处理器乘除法占时是比较长,后来硬件速度的确提高不少。

#14


指令时序表,最新的到 2011-06-08,可用在  http://www.agner.org/optimize/ 4. 里下载到;或者直接  http://www.agner.org/optimize/instruction_tables.pdf

#15


http://bbs.chinaunix.net/thread-2133668-1-1.html
上面的参考资料看了,一条除法指令才46个时钟周期,请问一下用什么算法能超过这个速度?
用模拟硬件除法的方法来写除法平均计算每一位两条指令好像不够...

#16


引用 11 楼 lacs34 的回复:
引用 4 楼 gsy999 的回复:
引用 3 楼 lacs34 的回复:
你是指用循环指令模拟除法指令?
那样不是会慢好多么?

正好相反,游戏程序的优化就是尽量把耗时的乘除法改为循环,因为乘除法用时很长,循环则很短,你看指令手册。

你们所说的指令手册是指《Intel® 64 and IA-32 Architectures Software Developer’s Manual》……

我做了个程序看了一下,用.lst 列表看了一下,在我的机子上
 0010   2   -- -- shr ax,1
 0012   2   -- -- rol ax,1
 0014 113+  -- -- idiv table

idiv 113+ ,加两个只有2

#17


咦,哪个汇编器能给出这个信息,好像还是基于 8086 的?看上面提及的那个手册里,45nm 制程的 Core2 象 div/idiv 这样的指令,除数是寄存器的话,16/32 的是 7 个微时序,8 位的才 4 个。其它的普通算术运算指令,对寄存器的操作,一般也需要 1-2 个时序的。
还真不能拿上古时代的资料来衡量当下的配置的。

#18


可以改成浮点除法运算,或者用SSE除法指令。

#19


据我所知,SSE好像没有除法指令。不过,如果除数是一个固定的数。可以采用以乘代除法,速度比直接使用除法快上很多。

#20


divss、divsd、divps、divpd

#21


sorry, 我没说清楚,我指的是SSE指令中没有整数除法指令。