IEEE-754 floating point exceptions in C

I am writing a floating point calculator in C that allows access to the math functions defined in math.h at runtime. The interface is implemented as a function that behaves like strtold (). It is based on ASCII and should be as portable as ASCII, but for this to be true, I need to handle floating points in the most portable way possible. I am pleased with the IEEE-754 floating point support limitation, but I am not sure how to handle the exceptions defined by IEEE-754 (overflow, overflow, etc.). First of all, Iโ€™m sure that the only way to check for exceptions that will work in all rounding modes is to check the status flags themselves; for this I need fenv.h (defined in Appendix F to C99), so I want to know how portable fenv.h is in practice.I also don't quite understand how fenv.h should work; It seems to me that the status flags are centralized, but for some reason I was under the impression that each floating point had built-in flags. I also know that C99 says that functions defined in math.h can overflow and overflow, but I don't understand how I should check for these exceptions. So, to summarize, I'm looking for an example of using fenv.h to check for overflow caused by multiplication, and an explanation of how to correctly check for function errors defined in math.h.how should I check for these exceptions. So, to summarize, I'm looking for an example of using fenv.h to check for overflow caused by multiplication, and an explanation of how to correctly check for function errors defined in math.h.how should I check for these exceptions. So, to summarize, I'm looking for an example of using fenv.h to check for overflow caused by multiplication, and an explanation of how to correctly check for function errors defined in math.h.

+4
source share
3 answers

In theory, the following function multiplies two numbers, returning trueif overflow occurred, and falseif not:

bool mul(double &a, double b) {
  feclearexcept(FE_OVERFLOW);
  a *= b;
  return fetestexcept(FE_OVERFLOW) != 0;
}

, #pragma FENV_ACCESS ON, . , , , , , --- gcc clang "" "", . gcc bug 34678 , , clang. , , .

+4

, :

  • reset

, , . :

double mul(double a, double b, int *status) {
    #pragma STDC FENV_ACCESS ON
    fexcept_t flags;
    int sv_status, f_status = -1;
    double resul;

    sv_status = fegetexceptflag(&flags, FE_ALL_EXCEPT) != 0; /* save flags */
    if (sv_status == 0) {
        f_status = feclearexcept(FE_ALL_EXCEPT);   /* clear all fp exception con
ditions */
    }
    resul = a * b;
    if (f_status == 0) {
        *status = fetestexcept(FE_ALL_EXCEPT); /* note conditions */
    }
    if (sv_status == 0) {
        fesetexceptflag(&flags, FE_ALL_EXCEPT); /* restore initial flags */
    }
    return resul;

}

:

int main ()
{
        double d2, d3, d4;
        int status;
        double d = 1e100;

        feraiseexcept(FE_OVERFLOW | FE_INEXACT);
        status = fetestexcept(FE_ALL_EXCEPT);
        printf("initial status : %x\n", status);
        d2 = mul(3., 4., &status);
        printf("resul 3 * 4 : %g - status %x (%x)\n", d2,
                status, fetestexcept(FE_ALL_EXCEPT));
        d2 = mul(d, d, &status);
        printf("resul d * d : %g - status %x (%x)\n", d2,
                status, fetestexcept(FE_ALL_EXCEPT));
        d2 = mul(d2, d, &status);
        printf("resul d *d *d : %g - status %x (%x)\n", d2,
                status, fetestexcept(FE_ALL_EXCEPT));
        d2 = mul(d2, d, &status);
        printf("resul d *d *d*d : %g - status %x (%x)\n", d2,
                status, fetestexcept(FE_ALL_EXCEPT));
        d2 = mul(d2, d, &status);
        printf("resul d *d *d*d*d : %g - status %x (%x)\n", d2,
                status, fetestexcept(FE_ALL_EXCEPT));
        return 0;
}

:

initial status : 28
resul 3 * 4 : 12 - status 0 (28)
resul d * d : 1e+200 - status 20 (28)
resul d *d *d : 1e+300 - status 20 (28)
resul d *d *d*d : inf - status 28 (28)
resul d *d *d*d*d : inf - status 0 (28)

, mul:

, C, , C99.

.

: ISO/IEC 9899: 201x (ISO C11)

Nota: Clang ( ) , STDS FENV_ACCESS,

+2

In reality, no one checks for floating point exceptions. Anyone who is interested (and this is a minority!) Checks the return values: you can easily check if the result is NaN, +/- infinity or a denormalized number. You will need to manually check to determine that zero is the result of multiplying or dividing nonzero numbers, but it's pretty simple.

One of the reasons that no one checks for exceptions is that it would be difficult for me to get it to work with any single compiler, and it's impossible to get it to work with many compilers.

+1
source

All Articles