从捕获浮点异常返回 [英] Returning From Catching A Floating Point Exception

查看:149
本文介绍了从捕获浮点异常返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我试图从浮点异常返回,但是我的代码却继续循环.我实际上可以退出该过程,但是我要做的是返回并重做导致浮点错误的计算.

So, I am trying to return from a floating point exception, but my code keeps looping instead. I can actually exit the process, but what I want to do is return and redo the calculation that causes the floating point error.

发生FPE的原因是因为我有一个随机数生成器,可以生成多项式的系数.使用一些LAPACK函数,我求根,然后做一些其他事情.在这个数学密集型链中的某个地方,会出现浮点异常.发生这种情况时,我想做的是增加随机数生成器的状态,然后重试直到系数不出现(通常不会出现),但很少出现并导致灾难性的结果.

The reason the FPE occurs is because I have a random number generator that generates coefficients for a polynomial. Using some LAPACK functions, I solve for the roots and do some other things. Somewhere in this math intensive chain, a floating point exception occurs. When this happens, what I want to do is increment the random number generator state, and try again until the coefficients are such that the error doesn't materialize, as it usually doesn't, but very rarely does and causes catastrophic results.

因此,我编写了一个简单的测试程序来学习如何处理信号.在下面:

So I wrote a simple test program to learn how to work with signals. It is below:

例外.h

#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H

#define _GNU_SOURCE

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <math.h>
#include <errno.h>
#include <float.h>
#include <fenv.h>

void overflow_handler(int);

#endif // EXCEPTIONS_H //

例外.c

#include "exceptions.h"

void overflow_handler(int signal_number)
{
    if (feclearexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO | FE_INVALID)){
        fprintf(stdout, "Nothing Cleared!\n");
    }
    else{
        fprintf(stdout, "All Cleared!\n");
    }

    return;
}

在main.c

#include "exceptions.h"


int main(void)
{
    int failure;
    float oops;

    //===Enable Exceptions===//
    failure = 1;
    failure = feenableexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO | FE_INVALID);
    if (failure){
        fprintf(stdout, "FE ENABLE EXCEPTIONS FAILED!\n");
    }

    //===Create Error Handler===//
    signal(SIGFPE, overflow_handler);

    //===Raise Exception===//
    oops = exp(-708.5);
    fprintf(stdout, "Oops: %f\n", oops);

    return 0;
}

Makefile

#===General Variables===#
CC=gcc
CFLAGS=-Wall -Wextra -g3 -Ofast

#===The Rules===#
all: makeAll

makeAll: makeExceptions makeMain
    $(CC) $(CFLAGS) exceptions.o main.o -o exceptions -ldl -lm

makeMain: main.c 
    $(CC) $(CFLAGS) -c main.c -o main.o

makeExceptions: exceptions.c exceptions.h
    $(CC) $(CFLAGS) -c exceptions.c -o exceptions.o 

.PHONY: clean

clean:
    rm -f *~ *.o

为什么我清除异常时该程序没有终止,据说成功了?为了返回主菜单并退出,该怎么办?

Why doesn't this program terminate when I am clearing the exceptions, supposedly successfully? What do I have to do in order to return to the main, and exit?

如果可以这样做,我可以在返回和退出之间插入代码,并在捕获FPE之后执行一些操作.我认为我将设置某种标志,然后根据是否设置了该标志,清除数据结构中的所有最新信息,重做计算等.关键是,真实程序不能永远中止或循环,而必须处理异常并继续运行.

If I can do this, I can put code in between returning and exiting, and do something after the FPE has been caught. I think that I will set some sort of flag, and then clear all most recent info in the data structures, redo the calculation etc based on whether or not that flag is set. The point is, the real program must not abort nor loop forever, but instead, must handle the exception and keep going.

帮助?

推荐答案

我想,如果您想跳过一条指令或退出 exp ,那么您应该弄乱调用堆栈框架管他呢.这是高级伏都教徒,注定是便携的.

I think you're supposed to mess around with the calling stack frame if you want to skip an instruction or break out of exp or whatever. This is high voodoo and bound to be unportable.

GNU C库让您在信号处理程序外部使用 setjmp(),您可以从内部对其进行 longjmp().这似乎是一个更好的方法.这是您的程序的独立修改,显示了如何执行此操作:

The GNU C library lets you use setjmp() outside of a signal handler to which you can longjmp() from inside. This seems like a better way to go. Here is a self-contained modification of your program showing how to do it:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <math.h>
#include <errno.h>
#include <float.h>
#include <fenv.h>

sigjmp_buf oh_snap;

void overflow_handler(int signal_number) {
    if (feclearexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO | FE_INVALID)){
        fprintf(stdout, "Nothing Cleared!\n");
    }
    else{
        fprintf(stdout, "All Cleared!\n");
    }
    siglongjmp(oh_snap, 1);

    return;
}

int main(void) {
    int failure;
    float oops;
    failure = 1;
    failure = feenableexcept(FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO | FE_INVALID);
    if (failure){
        fprintf(stdout, "FE ENABLE EXCEPTIONS FAILED!\n");
    }
    signal(SIGFPE, overflow_handler);
    if (sigsetjmp(oh_snap, 1)) {
      printf("Oh snap!\n");
    } else {
      oops = exp(-708.5);
      fprintf(stdout, "Oops: %f\n", oops);
    }
    return 0;
}

这篇关于从捕获浮点异常返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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