Programmiersprache C/C++

matherr

Einige C-Systeme bieten dem Programmierer an, mittels der Funktion matherr oder _matherr auf Fehler bei der Ausführung von mathematischen Standardfunktionen zu reagieren. Das Laufzeitsystem stellt eine Basisvariante dieser Funktion zur Verfügung, die vom Nutzer überschrieben werden kann.
matherr ist nicht in ANSI-C vorgesehen.

  #include <math.h>

  int _matherr (struct exception *e)
(z.B. Borland und Microsoft C-Systeme)

Die Struktur exception besitzt folgenden Aufbau:

  struct exception {
    int type;                     /* Art des Fehlers */
    char *name;                   /* Name der Funktion, in der ein
                                     Fehler aufgetreten ist */
    double arg1, arg2, retval;    /* 1. und 2. Parameter der Funktion, 
                                     Rückgabewert dieser Funktion */
  };
Rückgabewert:
  1    Funktionswert wurde korrigiert
       Programm arbeitet weiter, als wäre kein Fehler aufgetreten
  0    Funktionswert wurde nicht korrigiert
       Programm führt die vom C-System vorgesehene
       Standardfehlerbehandlung aus
Beispiel (Borland C++):
  #include <stdio.h>
  #include <stdlib.h>
  #include <math.h>

  int _matherr (struct exception *e)   /* Borland C */
  {
    char *msg[] =
    {
      "argument domain error",
      "argument singularity ",
      "overflow range error ",
      "underflow range error",
      "total loss of significance",
      "partial loss of significance"
    };

    union nan {
      unsigned short NANS[4];    /* NaN = Not a Number */
      double NAN;                /* NaN = 0x7FF8042000000000 */
    } NaN, Infp;

    /* NaN = 0x7FF8042000000000     Not a Number */
    NaN.s[0] = 0; NaN.s[1] = 0; NaN.s[2] = 0x0420; NaN.s[3] = 0x7FF8;

    /* Infp = 0x7FF0000000000000     +Infinite */
    Infp.s[0] = 0; Infp.s[1] = 0; Infp.s[2] = 0; Infp.s[3] = 0x7FF0;

    fprintf(stderr,
        "%s (%8g,%8g): %s\n", e->name, e->arg1, e->arg2, msg[e->type - 1]);

    switch ( e->type ) {
      case 3:
        e->retval = Infp.d; break;
      case 4:
        e->retval = 0; break;
      default:
        e->retval = NaN.d; break;
    }

    return 1;
  }

  int main(void)
  {
    printf("sin(1e1)   = %f \n", sin(1e1));
    printf("sin(1e10)  = %f \n", sin(1e10));
    printf("sin(1e100) = %f \n", sin(1e100));
    printf("\n");

    printf("exp(-10)   = %f \n", exp(-10));
    printf("exp(-100)  = %f \n", exp(-100));
    printf("exp(-1000) = %f \n", exp(-1000));
    printf("\n");

    printf("log(0)     = %f \n", log(0));
    printf("exp(10000) = %f \n", exp(10000));
    printf("End\n");

    return 0;
  }
Testergebnisse mit Borland C++ 4.5
  sin(1e1)   = -0.544021
  sin(1e10)  = -0.487506
  sin (  1e+100,       0): total loss of significance
  sin(1e100) = +NAN

  exp(-10)   = 0.000045
  exp(-100)  = 0.000000
  exp (   -1000,       0): underflow range error
  exp(-1000) = 0.000000

  log (       0,       0): argument singularity
  log(0)     = +NAN
  exp (   10000,       0): overflow range error
  exp(10000) = +INF
  End
Testergebnisse mit Borland C++ 4.5 ohne nutzerdefinierte Funktion _matherr
  sin(1e1)   = -0.544021
  sin(1e10)  = -0.487506
  sin(1e100) = +NAN

  exp(-10)   = 0.000045
  exp(-100)  = 0.000000
  exp(-1000) = 0.000000

  log: SING error
  log(0)     = -1.797693134862315708000000000000000000000e+308

  exp: OVERFLOW error
  exp(10000) = 1.797693134862315708000000000000000000000e+308
  End
Testergebnisse mit Microsoft C 6.0 ohne nutzerdefinierte Funktion _matherr
  sin(1e1)   = -0.544021
  sin: TLOSS error
  sin(1e10)  = 0.000000
  sin: TLOSS error
  sin(1e100) = 0.000000

  exp(-10)   = 0.000045
  exp(-100)  = 0.000000
  exp(-1000) = 0.000000

  log: SING error
  log(0)     = -179769313486231600000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  000.000000
  exp(10000) = 1797693134862316000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00.000000
  End
Eine alternative Möglichkeit aufgetretene Fehler festzustellen besteht eventuell darin, die Variable errno auszuwerten:
  #include <stdio.h>
  #include <stdlib.h>
  #include <math.h>
  #include <errno.h>

  void check(void)
  {
    if ( errno ) 
      printf("errno = %d\n", errno, _sys_errlist[errno]);
  }

  int main(void)
  {
    printf("sin(1e100) = %f \n", sin(1e100));   check();
    printf("exp(-1000) = %f \n", exp(-1000));   check();
    printf("log(0)     = %f \n", log(0));       check();
    printf("exp(10000) = %f \n", exp(10000));   check();

    return 0;
  }
Testergebnisse, Borland C++
  sin(1e100) = +NAN
  exp(-1000) = 0.000000

  log: SING error
  log(0)     = -1.797693134862315708000000000000000000000e+308
  errno = 34 : Result too large

  exp: OVERFLOW error
  exp(10000) = 1.797693134862315708000000000000000000000e+308
  errno = 34 : Result too large
Testergebnisse, Microsoft Visual C++ 1.0
  sin: TLOSS error
  sin(1e100) = 0.000000
  errno = 34 : Result too large
  exp(-1000) = 0.000000
  errno = 34 : Result too large
  log: SING error
  log(0)     = -179769313486231600000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  000.000000
  errno = 34 : Result too large
  exp(10000) = 1797693134862316000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00000000000000000000000000000000000000000000000000000000000000000000000000000000
  00.000000
  errno = 34 : Result too large
Testergebnisse, Gnu C unter DOS
  Floating Point exception at eip=1fdc
  eax=00004581 ebx=00054011 ecx=00000000 edx=00000066 esi=00051d20 edi=fffffff3
  ebp=00051cf8 esp=00050938 cs=b7 ds=af es=af fs=af gs=c7 ss=bf cr2=00001fea
  Call frame traceback EIPs:
    0x00001fdc
    0x000014ec
    0x00001244
Verschiedene C-Systeme stufen Ausnahmesituationen unterschiedlich ein und nehmen zum Teil sehr unterschiedliche Handlunngen vor.


Zurück zum Menü
Zurück zur vorigen Seite Weiter zur nächsten Seite

P. Böhme, 15.01.1996