[gelöst] Wie überschreiten des Wertebereichs richtig abfangen?



  • @;fricky
    Interessant zu wissen das es sowas gibt!
    Der Code soll jedoch auch von anderen Mitstudenten gelesen werden können, und deswegen benutze ich lieber die klassische, wenn auch nicht effiziente x*x*x*...*x*x*x Variante.

    Hier kann man den Artikel auch in deutsch finden:http://de.wikipedia.org/wiki/Bin%C3%A4re_Exponentiation



  • Äh...

    if(zwischenergebnis > INT_MAX / (double) basis) {
      return EXIT_FAILURE;
    }
    

    ?



  • seldon schrieb:

    Äh...

    if(zwischenergebnis > INT_MAX / (double) basis) {
      return EXIT_FAILURE;
    }
    

    ?

    ^^funzt doch auch nicht. schau mal hier: http://www.scipub.org/fulltext/jcs/jcs13304-309.pdf
    dritte seite, links unten: Overflow = (((a.. *fg*
    🙂



  • Das ganze jetzt so zu normalisieren, dass basis positiv ist, ist nun wirklich trivial, und für alle relevanten Fälle ist das zwischenergebnis >= basis, also reicht das so schon aus.



  • seldon schrieb:

    Das ganze jetzt so zu normalisieren, dass basis positiv ist, ist nun wirklich trivial, und für alle relevanten Fälle ist das zwischenergebnis >= basis, also reicht das so schon aus.

    ^^zeig doch mal ein komplettes beispiel, z.b. eine 'mult'-funktion, die überläufe erkennt.
    🙂



  • #include <limits.h>
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int hoch_aux(int *cache, unsigned basis, unsigned exponent) {
      if(exponent % 2 == 1) {
        if(hoch_aux(cache, basis, exponent - 1) || *cache > INT_MAX / (double) basis) {
          return EXIT_FAILURE;
        }
    
        *cache *= basis;
      } else if(exponent != 0) {
        static double intmax_sqrt = sqrt(INT_MAX);
    
        if(hoch_aux(cache, basis, exponent / 2) || *cache > intmax_sqrt) {
          return EXIT_FAILURE;
        }
    
        *cache *= *cache;
      }
    
      return EXIT_SUCCESS;
    }
    
    int hoch(int *result, int basis, unsigned exponent) {
      int cache = 1, err = EXIT_FAILURE;
    
      err = hoch_aux(&cache, abs(basis), exponent);
      cache *= 1 - 2 * (basis < 0 && exponent % 2 == 0);
    
      if(err == EXIT_SUCCESS) {
        *result = cache;
      }
    
      return err;
    }
    
    int main(int argc, char *argv[]) {
      int x;
    
      if(argc == 3 && !hoch(&x, atoi(argv[1]), atoi(argv[2]))) {
        printf("%d\n", x);
      } else {
        return -1;
      }
    
      return 0;
    }
    


  • ^^mag ja sein dass dein code geht, aber der ist ja wohl viel komplizierter als die anderen vorschläge hier. *fg*
    🙂



  • Wenn Performance und Fehlerfall-Garantien dich nicht interessieren, kannst du's auf

    int hoch_aux(int *cache, unsigned basis, unsigned exponent) {
      if(exponent == 0) return EXIT_SUCCESS;
    
      if(hoch_aux(cache, basis, exponent - 1) || *cache > INT_MAX / (double) basis) {
        return EXIT_FAILURE;
      }
    
      *cache *= basis;
    
      return EXIT_SUCCESS;
    }
    
    int hoch(int *result, int basis, unsigned exponent) {
      int err;
    
      err = hoch_aux(result, abs(basis), exponent);
      *result *= 1 - 2 * (basis < 0 && exponent % 2 == 0);
    
      return err;
    }
    

    zusammenstreichen, aber ich halte es nicht für sinnvoll, derart dreckige Praktiken zu verbreiten.



  • seldon schrieb:

    aber ich halte es nicht für sinnvoll, derart dreckige Praktiken zu verbreiten.

    hab's mal ausprobiert, der zweite code tuts nicht bei mir. der erste aber schon.
    🙂



  • Eh, tschuldigung.

    int hoch(int *result, int basis, unsigned exponent) {
      int err;
    
      *result = 1; /* <-- hier */
      err = hoch_aux(result, abs(basis), exponent);
      *result *= 1 - 2 * (basis < 0 && exponent % 2 == 0);
    
      return err;
    }
    


  • ach du heiliges potenzmittel. erst ein abs, damit der grösser-vergleich geht, dann alles auf 'double' aufblasen und mit dem: *result *= 1 - 2 * (basis < 0 && exponent % 2 == 0) wird am schluss das vorzeichen wiederhergestellt, ne? das ist doch etwas zu umständlich, finde ich. *fg*
    🙂



  • Erstens ist abs beim besten Willen kein komplexes Konstrukt. Zweitens wird nichts auf double aufgeblasen, ich benutze nur einen Cast, um eine Integer-Division zu umgehen. Wo ich mir das grad so ankucke, ist das aber eigentlich nicht mal notwendig. Drittens, wenn dir das Zerlegen eines Problems in einfachere Teilprobleme zu hoch ist, solltest du die Wahl deiner beruflichen Laufbahn überdenken, denn als Programmierer hast du dann keine Zukunft.

    Im Übrigen hat diese Lösung den Vorteil, dass ihr Verhalten definiert ist. Das ist bei allen, die erst einen Overflow provozieren und danach prüfen, ob einer aufgetreten ist, nicht der Fall (vgl. 3.4.3 im C99-Standard).



  • seldon schrieb:

    Drittens, wenn dir das Zerlegen eines Problems in einfachere Teilprobleme zu hoch ist, solltest du die Wahl deiner beruflichen Laufbahn überdenken, denn als Programmierer hast du dann keine Zukunft.

    na, da hab ich ja glück, dass ich nur nebenbei programmieren darf. übrigens können wir uns die hand reichen, deine vorzeichen-rekonstruktion tut's nämlich auch nicht so richtig. *fg*

    seldon schrieb:

    Im Übrigen hat diese Lösung den Vorteil, dass ihr Verhalten definiert ist. Das ist bei allen, die erst einen Overflow provozieren und danach prüfen, ob einer aufgetreten ist, nicht der Fall (vgl. 3.4.3 im C99-Standard).

    ich hab doch weiter oben ein .pdf gepostet. da steht z.b. auch drin, wie man overflows vor der multiplikation abfangen kann.
    🙂


Anmelden zum Antworten