#line 1 "intplus.d"
/* Addition/Subtraktion von Integers */

/* Macro: In der DS MSDptr/len/LSDptr wird eine 1 unterhalb des Pointers ptr */
/* addiert. Unterhalb von MSDptr muss 1 Digit Platz sein. */
/* Dabei ist  ptr - MSDptr = count  und  0 < count <= len . */
/* Eventuell wird MSDptr erniedrigt und len erhöht. */
  #define DS_1_plus(ptr,count)  \
    {                                                                      \
      var uintD* ptr_from_DS_1_plus = (ptr);                               \
      var uintC count_from_DS_1_plus = (count);                            \
      while (1) {                                                          \
        if (--count_from_DS_1_plus==0) { /* Zähler erniedrigen               */\
          /* Beim Most Significant Digit angelangt                           */\
          *(--ptr_from_DS_1_plus) += 1;                                    \
          /* jetzt ist ptr_from_DS_1_plus = MSDptr                           */\
          if (*ptr_from_DS_1_plus == bit(intDsize-1)) {                    \
            /* 7FFF + 1 muss zu 00008000 werden:                             */\
            *--MSDptr = 0;                                                 \
            len++;                                                         \
            if (uintWCoverflow(len)) {                                     \
              RESTORE_NUM_STACK; BN_ueberlauf();                           \
            }                                                              \
          }                                                                \
          break;                                                           \
        }                                                                  \
        if (!((*(--ptr_from_DS_1_plus) += 1) == 0)) /* weiterincrementieren  */\
          break; /* kein weiterer Übertrag -> Schleife abbrechen             */\
      }                                                                    \
    }

/* Macro: In der DS MSDptr/len/LSDptr wird eine 1 unterhalb des Pointers ptr */
/* subtrahiert. Unterhalb von MSDptr muss 1 Digit Platz sein. */
/* Dabei ist  ptr - MSDptr = count  und  0 < count <= len . */
/* Eventuell wird MSDptr erniedrigt und len erhöht. */
  #define DS_minus1_plus(ptr,count)  \
    {                                                                 \
      var uintD* ptr_from_DS_minus1_plus = (ptr);                     \
      var uintC count_from_DS_minus1_plus = (count);                  \
      while (1) {                                                     \
        if (--count_from_DS_minus1_plus==0) { /* Zähler erniedrigen     */\
          /* Beim Most Significant Digit angelangt                      */\
          *(--ptr_from_DS_minus1_plus) -= 1;                          \
          /* jetzt ist ptr_from_DS_minus1_plus = MSDptr                 */\
          if (*ptr_from_DS_minus1_plus == (uintD)bit(intDsize-1)-1) { \
            /* 8000 - 1 muss zu FFFF7FFF werden:                        */\
            *--MSDptr = (uintD)(-1);                                  \
            len++;                                                    \
            if (uintWCoverflow(len)) {                                \
              RESTORE_NUM_STACK; BN_ueberlauf();                      \
            }                                                         \
          }                                                           \
          break;                                                      \
        }                                                             \
        if (!((sintD)(*(--ptr_from_DS_minus1_plus) -= 1) == -1)) /* weiterdecrementieren  */\
          break; /* kein weiterer Übertrag -> Schleife abbrechen        */\
      }                                                               \
    }

/* (1+ x), wo x ein Integer ist. Ergebnis Integer. */
/* can trigger GC */
modexp maygc object I_1_plus_I (object x)
  { GCTRIGGER1(x); {
    if (I_fixnump(x)) {
      /* x ist Fixnum */
      if (eq(x,Fixnum_minus1))
        return Fixnum_0; /* (1+ -1) = 0 */
      if (!eq(x,Fixnum_mpos))
        return fixnum_inc(x,1); /* bleibt Fixnum: direkt 1 addieren */
    }
    /* die sichere Methode */
    {
      SAVE_NUM_STACK /* num_stack retten */
      var uintD* MSDptr;
      {var uintC len;
      {var uintD* LSDptr;
      I_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden. */
      DS_1_plus(LSDptr,len); /* zur NDS 1 addieren */
      {var object result = DS_to_I(MSDptr,len); /* wieder zum Integer machen */
      RESTORE_NUM_STACK /* num_stack zurück */
      return result;
    }}}}
  }}

/* (1- x), wo x ein Integer ist. Ergebnis Integer. */
/* can trigger GC */
modexp maygc object I_minus1_plus_I (object x)
  { GCTRIGGER1(x); {
    if (I_fixnump(x)) {
      /* x ist Fixnum */
      if (eq(x,Fixnum_0))
        return Fixnum_minus1; /* (1- 0) = -1 */
      if (!eq(x,Fixnum_mneg))
        return fixnum_inc(x,-1); /* bleibt Fixnum: direkt 1 subtrahieren */
    }
    /* die sichere Methode */
    {
      SAVE_NUM_STACK /* num_stack retten */
      var uintD* MSDptr;
      {var uintC len;
      {var uintD* LSDptr;
      I_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden. */
      DS_minus1_plus(LSDptr,len); /* von der NDS 1 subtrahieren */
      {var object result = DS_to_I(MSDptr,len); /* wieder zum Integer machen */
      RESTORE_NUM_STACK /* num_stack zurück */
      return result;
    }}}}
  }}

/* (+ x y), wo x und y Integers sind. Ergebnis Integer. */
/* can trigger GC */
modexp maygc object I_I_plus_I (object x, object y)
  { GCTRIGGER2(x,y); {
    /* Methode: */
    /* x Fixnum -> */
    /*   y Fixnum -> beide direkt addieren, mit L_to_I beenden */
    /*   y Bignum -> falls x=0, y; sonst beide zu DS machen, addieren. */
    /* x Bignum -> */
    /*   y Fixnum -> falls y=0, x; sonst beide zu DS machen, addieren. */
    /*   y Bignum -> beide zu DS machen, addieren. */
    {var uintD* MSDptr;
    {var uintC len;
    {var uintD* LSDptr;
    /* MSDptr/len/LSDptr bilden die DS des Ergebnisses. */
    if (I_fixnump(x)) {
      /* x ist Fixnum */
      if (I_fixnump(y)) {
        /* x,y sind Fixnums */
        #if (oint_data_len+1 < intVsize)
        return V_to_I( FN_to_V(x) + FN_to_V(y) ); /* als intVsize-Bit-Zahlen addieren */
        #elif defined(intQsize)
        return Q_to_I( FN_to_Q(x) + FN_to_Q(y) ); /* als 64-Bit-Zahlen addieren */
        #elif (intVsize==32)
        {var sint32 xhi = FN_sign(x);
        {var uint32 xlo = FN_to_V(x);
        {var sint32 yhi = FN_sign(y);
        {var uint32 ylo = FN_to_V(y);
        xhi += yhi;
        xlo += ylo;
        if (xlo < ylo)
          xhi += 1;
        return L2_to_I(xhi,xlo);
        #endif
      
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#line 143
} else {
        /* x ist Fixnum, y ist Bignum */
        {var object h; h = x; x = y; y = h; /* x und y vertauschen */
        goto xBN_yFN;
      }}
    } else {
      /* x ist Bignum */
      if (I_fixnump(y))
      xBN_yFN: {
        /* x ist Bignum, y ist Fixnum, also x länger */
        {var sintV y_ = FN_to_V(y); /* Wert von y */
        if (FN_V_zerop(y,y_))
          return x; /* bei y=0 Ergebnis x */
        {
          SAVE_NUM_STACK /* num_stack retten */
          BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden. */
          /* len>=bn_minlength. len>pFN_maxlength erzwingen: */
          if ((bn_minlength==pFN_maxlength) && (len==pFN_maxlength)) {
            {var sintD sign = sign_of_sintD(MSDptr[0]);
            *--MSDptr = sign; len++;
          }}
          /* y_ zu den oberen pFN_maxlength Digits von x addieren: */
          {
            {var uintD* midptr = &LSDptr[-(uintP)pFN_maxlength];
            {var uintV x_ = pFN_maxlength_digits_at(midptr);
            {var uintV x_new = x_+(uintV)y_;
            set_pFN_maxlength_digits_at(midptr,x_new);
            if (x_new < x_) {
              /* Carry. */
              if (!FN_V_minusp(y,y_)) { /* kürzerer Summand war positiv */
                /* Dann ist ein positiver Übertrag weiterzutragen */
                /* (Beispiel: 0002FFFC + 0007 = 00030003) */
                DS_1_plus(midptr,len-pFN_maxlength);
              }
            } else {
              /* Kein Carry. */
              if (FN_V_minusp(y,y_)) { /* kürzerer Summand war negativ */
                /* Dann ist ein negativer Übertrag weiterzutragen */
                /* (Beispiel: 00020003 + FFF5 = 0001FFF8) */
                DS_minus1_plus(midptr,len-pFN_maxlength);
              }
            }
          }}}}
          {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
          RESTORE_NUM_STACK /* num_stack zurück */
          return result;
        }}
      }} else {
        /* x und y sind Bignums */
        SAVE_NUM_STACK /* num_stack retten */
        if (Bignum_length(x) < Bignum_length(y)) {
          {var object h; h = x; x = y; y = h; /* x und y vertauschen */
        }}
        /* Nun ist x das längere von beiden. */
        BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden. */
        {var uintD* yMSDptr;
        {var uintC ylen;
        {var uintD* yLSDptr;
        BN_to_NDS_nocopy(y, yMSDptr=,ylen=,yLSDptr=); /* NDS zu y bilden. */
        /* yMSDptr/ylen/yLSDptr bilden die DS des kürzeren Arguments y. */
        /* len>ylen erzwingen: */
        if (len==ylen) {
          {var sintD sign = sign_of_sintD(MSDptr[0]);
          *--MSDptr = sign;
          len++;
          if (uintWCoverflow(len)) {
            RESTORE_NUM_STACK; BN_ueberlauf();
          }
        }}
        /* addieren: */
        {
          {var uintD* midptr = LSDptr-(uintP)ylen;
          {var uintD carry = addto_loop_down(yLSDptr,LSDptr,ylen);
          if (carry) {
            /* Carry. */
            if ((sintD)yMSDptr[0] >=0) { /* kürzerer Summand war positiv */
              /* Dann ist ein positiver Übertrag weiterzutragen */
              /* (Beispiel: 0002FFFC + 0007 = 00030003) */
              DS_1_plus(midptr,len-ylen);
            }
          } else {
            /* Kein Carry. */
            if ((sintD)yMSDptr[0] <0) { /* kürzerer Summand war negativ */
              /* Dann ist ein negativer Übertrag weiterzutragen */
              /* (Beispiel: 00020003 + FFF5 = 0001FFF8) */
              DS_minus1_plus(midptr,len-ylen);
            }
          }
        }}}
        {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
        RESTORE_NUM_STACK /* num_stack zurück */
        return result;
      }}}}}
    }
  }}}}}

/* (- x), wenn x ein Integer ist. Ergebnis Integer. */
/* can trigger GC */
  local maygc object I_minus_I (object x)
  { GCTRIGGER1(x); {
    if (I_fixnump(x)) {
      /* Fixnum -> Long, negieren, -> Integer */
      #if (oint_data_len+1 < intVsize)
      return V_to_I(- FN_to_V(x));
      #elif defined(intQsize)
      return Q_to_I(- FN_to_Q(x));
      #elif (intVsize==32)
      {var sint32 xhi = FN_sign(x);
      {var uint32 xlo = FN_to_V(x);
      if (xlo==0) {
        xhi = -xhi;
      } else {
        xlo = -xlo; xhi = ~xhi;
      }
      return L2_to_I(xhi,xlo);
      #endif
    
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#line 259
} else {
      /* x Bignum */
      SAVE_NUM_STACK /* num_stack retten */
      var uintD* MSDptr;
      {var uintC len;
      {var uintD* LSDptr;
      BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden, len>0 */
      /* vorsorglich 1 Digit mehr belegen: */
      {
        {var sintD sign = sign_of_sintD(MSDptr[0]);
        *--MSDptr = sign;
        len++;
        if (uintWCoverflow(len)) {
          RESTORE_NUM_STACK; BN_ueberlauf();
        }
      }}
      /* Negierschleife: */
      neg_loop_down(LSDptr,len);
      /* MSDigit ist nun = 0x0000 oder = 0xFFFF */
      {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
      RESTORE_NUM_STACK /* num_stack zurück */
      return result;
    }}}}
  }}

/* (- x y), wo x und y Integers sind. Ergebnis Integer. */
/* can trigger GC */
modexp maygc object I_I_minus_I (object x, object y)
  { GCTRIGGER2(x,y); {
    /* Methode: */
    /* x Fixnum -> */
    /*   y Fixnum -> beide direkt subtrahieren, mit L_to_I beenden */
    /*   y Bignum -> falls x=0, (- y); sonst beide zu DS machen, subtrahieren. */
    /* x Bignum -> */
    /*   y Fixnum -> falls y=0, x; sonst beide zu DS machen, subtrahieren. */
    /*   y Bignum -> beide zu DS machen, subtrahieren. */
    {var uintD* MSDptr;
    {var uintC len;
    {var uintD* LSDptr;
    /* MSDptr/len/LSDptr bilden die DS des Ergebnisses. */
    if (I_fixnump(x)) {
      /* x ist Fixnum */
      if (I_fixnump(y)) {
        /* x,y sind Fixnums */
        #if (oint_data_len+1 < intVsize)
        return V_to_I( FN_to_V(x) - FN_to_V(y) ); /* als intVsize-Bit-Zahlen subtrahieren */
        #elif defined(intQsize)
        return Q_to_I( FN_to_Q(x) - FN_to_Q(y) ); /* als 64-Bit-Zahlen subtrahieren */
        #elif (intVsize==32)
        {var sint32 xhi = FN_sign(x);
        {var uint32 xlo = FN_to_V(x);
        {var sint32 yhi = FN_sign(y);
        {var uint32 ylo = FN_to_V(y);
        xhi -= yhi;
        if (xlo < ylo)
          xhi -= 1;
        xlo -= ylo;
        return L2_to_I(xhi,xlo);
        #endif
      
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#if (!((oint_data_len+1 < intVsize))) && (!(defined(intQsize))) && ((intVsize==32))
}
#endif
#line 318
} else {
        /* x ist Fixnum, y ist Bignum, also y länger */
        {var sintV x_ = FN_to_V(x); /* Wert von x */
        if (FN_V_zerop(x,x_))
          return I_minus_I(y); /* bei x=0 Ergebnis (- y) */
        {
          SAVE_NUM_STACK /* num_stack retten */
          BN_to_NDS_1(y, MSDptr=,len=,LSDptr=); /* NDS zu y bilden. */
          /* vorsorglich 1 Digit mehr belegen: */
          {
            {var sintD sign = sign_of_sintD(MSDptr[0]);
            *--MSDptr = sign;
            len++;
            if (uintWCoverflow(len)) {
              RESTORE_NUM_STACK; BN_ueberlauf();
            }
          }}
          /* Negierschleife: */
          neg_loop_down(LSDptr,len);
          /* MSDigit ist nun = 0x0000 oder = 0xFFFF */
          /* x_ zu den oberen pFN_maxlength Digits von -y addieren: */
          {
            {var uintD* midptr = &LSDptr[-(uintP)pFN_maxlength];
            {var uintV y_ = pFN_maxlength_digits_at(midptr);
            {var uintV y_new = y_+(uintV)x_;
            set_pFN_maxlength_digits_at(midptr,y_new);
            if (y_new < y_) {
              /* Carry. */
              if (!FN_V_minusp(x,x_)) { /* kürzerer Summand war positiv */
                /* Dann ist ein positiver Übertrag weiterzutragen */
                /* (Beispiel: 0002FFFC + 0007 = 00030003) */
                DS_1_plus(midptr,len-pFN_maxlength);
              }
            } else {
              /* Kein Carry. */
              if (FN_V_minusp(x,x_)) { /* kürzerer Summand war negativ */
                /* Dann ist ein negativer Übertrag weiterzutragen */
                /* (Beispiel: 00020003 + FFF5 = 0001FFF8) */
                DS_minus1_plus(midptr,len-pFN_maxlength);
              }
            }
          }}}}
          {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
          RESTORE_NUM_STACK /* num_stack zurück */
          return result;
        }}
      }}
    } else {
      /* x ist Bignum */
      if (I_fixnump(y)) {
        /* x ist Bignum, y ist Fixnum, also x länger */
        {var sintV y_ = FN_to_V(y); /* Wert von y */
        if (FN_V_zerop(y,y_))
          return x; /* bei y=0 Ergebnis x */
        {
          SAVE_NUM_STACK /* num_stack retten */
          BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden. */
          /* len>=bn_minlength. len>pFN_maxlength erzwingen: */
          if ((bn_minlength==pFN_maxlength) && (len==pFN_maxlength)) {
            {var sintD sign = sign_of_sintD(MSDptr[0]);
            *--MSDptr = sign; len++;
          }}
          /* y_ von den oberen pFN_maxlength Digits von x subtrahieren: */
          {
            {var uintD* midptr = &LSDptr[-(uintP)pFN_maxlength];
            {var uintV x_ = pFN_maxlength_digits_at(midptr);
            {var uintV x_new = x_-(uintV)y_;
            set_pFN_maxlength_digits_at(midptr,x_new);
            if (x_new > x_) { /* bzw. (x_ < (uintV)y_), da y_>0 */
              /* Carry. */
              if (!FN_V_minusp(y,y_)) { /* kürzerer Summand war positiv */
                /* Dann ist ein negativer Übertrag weiterzutragen */
                /* (Beispiel: 00030003 - 0007 = 0002FFFC) */
                DS_minus1_plus(midptr,len-pFN_maxlength);
              }
            } else {
              /* Kein Carry. */
              if (FN_V_minusp(y,y_)) { /* kürzerer Summand war negativ */
                /* Dann ist ein positiver Übertrag weiterzutragen */
                /* (Beispiel: 0002FFF8 - FFF5 = 00030003) */
                DS_1_plus(midptr,len-pFN_maxlength);
              }
            }
          }}}}
          {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
          RESTORE_NUM_STACK /* num_stack zurück */
          return result;
        }}
      }} else {
        /* x und y sind Bignums */
        if (Bignum_length(x) > Bignum_length(y)) {
          /* x das längere von beiden. */
          SAVE_NUM_STACK /* num_stack retten */
          BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); /* NDS zu x bilden. */
          {var uintD* yMSDptr;
          {var uintC ylen;
          {var uintD* yLSDptr;
          BN_to_NDS_nocopy(y, yMSDptr=,ylen=,yLSDptr=); /* NDS zu y bilden. */
          /* yMSDptr/ylen/yLSDptr bilden die DS des kürzeren Arguments y. */
          /* Es ist len>ylen. */
          /* subtrahieren: */
          {
            {var uintD* midptr = LSDptr-(uintP)ylen;
            {var uintD carry = subfrom_loop_down(yLSDptr,LSDptr,ylen);
            if (carry) {
              /* Carry. */
              if ((sintD)yMSDptr[0] >=0) { /* kürzerer Summand war positiv */
                /* Dann ist ein negativer Übertrag weiterzutragen */
                /* (Beispiel: 00030003 - 0007 = 0002FFFC) */
                DS_minus1_plus(midptr,len-ylen);
              }
            } else {
              /* Kein Carry. */
              if ((sintD)yMSDptr[0] <0) { /* kürzerer Summand war negativ */
                /* Dann ist ein positiver Übertrag weiterzutragen */
                /* (Beispiel: 0002FFF8 - FFF5 = 00030003) */
                DS_1_plus(midptr,len-ylen);
              }
            }
          }}}
          {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
          RESTORE_NUM_STACK /* num_stack zurück */
          return result;
        }}}}} else {
          /* y das längere von beiden. */
          SAVE_NUM_STACK /* num_stack retten */
          BN_to_NDS_1(y, MSDptr=,len=,LSDptr=); /* NDS zu y bilden. */
          /* vorsorglich 1 Digit mehr belegen: */
          {
            {var sintD sign = sign_of_sintD(MSDptr[0]);
            *--MSDptr = sign;
            len++;
            if (uintWCoverflow(len)) {
              RESTORE_NUM_STACK; BN_ueberlauf();
            }
          }}
          /* Negierschleife: */
          neg_loop_down(LSDptr,len);
          /* MSDigit ist nun = 0x0000 oder = 0xFFFF */
          {var uintD* xMSDptr;
          {var uintC xlen;
          {var uintD* xLSDptr;
          BN_to_NDS_nocopy(x, xMSDptr=,xlen=,xLSDptr=); /* NDS zu x bilden. */
          /* xMSDptr/xlen/xLSDptr bilden die DS des kürzeren Arguments x. */
          /* Es ist jetzt len>xlen. */
          /* addieren: */
          {
            {var uintD* midptr = LSDptr-(uintP)xlen;
            {var uintD carry = addto_loop_down(xLSDptr,LSDptr,xlen);
            if (carry) {
              /* Carry. */
              if ((sintD)xMSDptr[0] >=0) { /* kürzerer Summand war positiv */
                /* Dann ist ein positiver Übertrag weiterzutragen */
                /* (Beispiel: 0002FFFC + 0007 = 00030003) */
                DS_1_plus(midptr,len-xlen);
              }
            } else {
              /* Kein Carry. */
              if ((sintD)xMSDptr[0] <0) { /* kürzerer Summand war negativ */
                /* Dann ist ein negativer Übertrag weiterzutragen */
                /* (Beispiel: 00020003 + FFF5 = 0001FFF8) */
                DS_minus1_plus(midptr,len-xlen);
              }
            }
          }}}
          {var object result = DS_to_I(MSDptr,len); /* DS wieder zum Integer machen */
          RESTORE_NUM_STACK /* num_stack zurück */
          return result;
        }}}}}
      }
    }
  }}}}}

/* (abs x), wenn x ein Integer ist. Ergebnis Integer. */
/* can trigger GC */
  local maygc object I_abs_I (object x)
  { GCTRIGGER1(x); {
    /* Methode: */
    /* Bei x<0: (- x), sonst x. */
    if (R_minusp(x))
      return I_minus_I(x);
    else
      return x;
  }}

