# Arithmetik, Level 0
# operiert auf einzelnen 16-Bit-Wörtern und 32-Bit-Wörtern (unsigned).

# Vorzeichen einer 32-Bit-Zahl bestimmen
# sign_of_sint32(wert)
# > wert: eine 32-Bit-Zahl
# < sint16 ergebnis: 0 falls wert>=0, -1 falls wert<0.
  extern sint16 sign_of_sint32 (sint32 wert);
# im 68000-Assembler (Input D0.L, Output D0.W):
#   SWAP D0  # Vorzeichen nach Bit 15 schieben
#   EXT.L D0 # nach Bit 31..16 kopieren
#   SWAP D0  # nach Bit 15..0 schieben
  #if defined(GNU) && defined(MC680X0) && !defined(NO_ASM)
    #define sign_of_sint32(wert)  \
      ({var sint32 __wert = (wert);  \
        var sint16 __ergebnis;        \
        __asm__ ("\
          swap %0;  \
          extl %0;  \
          swap %0   \
          " : "=d" (__ergebnis) : "0" (__wert));  \
        __ergebnis;                               \
       })
  #elif defined(SPARC) || defined(ARM) || defined(I80Z86) # I80Z86: umgeht Bug in Coherent386 cc, das sonst in SF_to_I auftaucht
    #define sign_of_sint32(wert)  (((sint32)(wert)) >> 31)
  #else
    #define sign_of_sint32(wert)  ((sint32)(wert) >= 0 ? 0 : -1)
  #endif

# Vorzeichen einer 16-Bit-Zahl bestimmen
# sign_of_sint16(wert)
# > wert: eine 16-Bit-Zahl
# < sint16 ergebnis: 0 falls wert>=0, -1 falls wert<0.
  extern sint16 sign_of_sint16 (sint16 wert);
# im 68000-Assembler (Input D0.W, Output D0.W):
#   EXT.L D0 # Vorzeichen nach Bit 31..16 kopieren
#   SWAP D0  # nach Bit 15..0 schieben
  #if defined(GNU) && defined(MC680X0) && !defined(NO_ASM)
    #define sign_of_sint16(wert)  \
      ({var sint16 __wert = (wert);  \
        var sint16 __ergebnis;        \
        __asm__ ("\
          extl %0;  \
          swap %0   \
          " : "=d" (__ergebnis) : "0" (__wert));  \
        __ergebnis;                               \
       })
  #elif defined(SPARC)
    #define sign_of_sint16(wert)  (((sint32)(sint16)(wert)) >> 31)
  #else
    #define sign_of_sint16(wert)  ((sint16)(wert) >= 0 ? 0 : -1)
  #endif

# High-Word einer 32-Bit-Zahl bestimmen
# high16(wert)
  extern uint16 high16 (uint32 wert);
# im 68000-Assembler (Input D0.L, Output D0.W):
#   SWAP D0
  #ifdef GNU
    #if defined(MC680X0) && !defined(NO_ASM)
      #define high16(wert)  \
        ({var uint32 __wert = (wert);  \
          var uint16 __ergebnis;        \
          __asm__ ("\
            swap %0   \
            " : "=d" (__ergebnis) : "0" (__wert));  \
          __ergebnis;                               \
         })
    #endif
  #endif
  #ifndef high16
    #define high16(wert)  ((uint16)((uint32)(wert)>>16))
  #endif

# Low-Word einer 32-Bit-Zahl bestimmen
# low16(wert)
  extern uint16 low16 (uint32 wert);
  #define low16(wert)  ((uint16)(uint32)(wert))

# Eine 32-Bit-Zahl aus ihrem High-Word und ihrem Low-Word bestimmen:
# highlow32(uint16 high, uint16 low)
  extern uint32 highlow32 (uint16 high, uint16 low);
# im 68000-Assembler (Input D0.W,D1.W, Output D0.L):
#   SWAP D0
#   MOVE.W D1,D0
  #ifdef GNU
    #if defined(MC680X0) && !defined(NO_ASM)
      #define highlow32(high,low)  \
        ({var uint16 __high = (high);  \
          var uint16 __low = (low);    \
          var uint32 __ergebnis;       \
          __asm__ __volatile__ ("\
            swap %0;     \
            movew %2,%0  \
            " : "=&d" (__ergebnis) : "0" (__high), "g" (__low));  \
          __ergebnis;                                             \
         })
    #endif
  #endif
  #ifndef highlow32
    #define highlow32(high,low)  \
      (((uint32)(uint16)(high) << 16) | (uint32)(uint16)(low))
  #endif

# Eine 32-Bit-Zahl aus ihrem High-Word und ihrem Low-Word 0 bestimmen:
# highlow32_0(uint16 high)
  extern uint32 highlow32_0 (uint16 high);
  # define highlow32_0(high)  highlow32(high,0)
# im 68000-Assembler (Input D0.W,D1.W, Output D0.L):
#   SWAP D0
#   CLR.W D0
  #ifdef GNU
    #if defined(MC680X0) && !defined(NO_ASM)
      #define highlow32_0(high)  \
        ({var uint16 __high = (high);  \
          var uint32 __ergebnis;       \
          __asm__ __volatile__ ("\
            swap %0;     \
            clrw %0      \
            " : "=d" (__ergebnis) : "0" (__high));  \
          __ergebnis;                               \
         })
    #endif
  #endif
  #ifndef highlow32_0
    #define highlow32_0(high)  ((uint32)(uint16)(high) << 16)
  #endif

# Multipliziert zwei 16-Bit-Zahlen miteinander und liefert eine 32-Bit-Zahl:
# mulu16(arg1,arg2)
# > arg1, arg2 : zwei 16-Bit-Zahlen
# < ergebnis: eine 32-Bit-Zahl
  extern uint32 mulu16 (uint16 arg1, uint16 arg2);
# in 68000-Assembler (Input D0.W, D1.W, Output D0.L):
#   MULU D1,D0
  #ifdef GNU
    #if defined(SPARC) && defined(FAST_DOUBLE) # Ist das schneller als _mulu16 ??
      #define mulu16(arg1,arg2)  \
        ({var union { double f; uint32 i[2]; } __fi; \
          __fi.f = (double)(sint32)(uint16)(arg1)*(double)(sint32)(uint16)(arg2) \
                   + (double)(4503599627370496.0L); # + 2^52, zum Normalisieren  \
          __fi.i[1]; # untere 32 Bit herausholen (benutzt BIG_ENDIAN_P !)        \
         })
    #elif defined(I80Z86) && !defined(NO_ASM)
      #define mulu16(arg1,arg2)  \
        ({ var register uint16 _hi;                                         \
           var register uint16 _lo;                                         \
           __asm__("mulw %2"                                                \
                   : "=d" /* %dx */ (_hi), "=a" /* %ax */ (_lo)             \
                   : "rm" ((uint16)(arg1)), "1" /* %eax */ ((uint16)(arg2)) \
                  );                                                        \
           highlow32(_hi,_lo);                                              \
         })
    #endif
  #else
    #if defined(SPARC)
      #define mulu16  mulu16_  # extern in Assembler
    #endif
  #endif
  #ifndef mulu16
    #define mulu16(arg1,arg2)  ((uint32)(uint16)(arg1)*(uint32)(uint16)(arg2))
  #endif

# Multipliziert zwei 24-Bit-Zahlen zusammen und liefert eine 48-Bit-Zahl.
# mulu24(arg1,arg2,hi=,lo=);
# > arg1, arg2 : zwei 24-Bit-Zahlen
# < 2^32*hi+lo : eine 48-Bit-Zahl
  #if defined(SPARC) && defined(FAST_DOUBLE)
    #define mulu24(x,y,hi_zuweisung,lo_zuweisung)  \
      { var reg1 uint32 _x = (x);                                                       \
        var reg2 uint32 _y = (y);                                                       \
        var union { double f; uint32 i[2]; uint16 s[4]; } __fi;                         \
        __fi.f = (double)(sint32)(_x)*(double)(sint32)(_y)                              \
                 + (double)(4503599627370496.0L); # + 2^52, zum Normalisieren           \
        hi_zuweisung __fi.s[1]; # mittlere 16 Bit herausholen, (benutzt BIG_ENDIAN_P !) \
        lo_zuweisung __fi.i[1]; # untere 32 Bit herausholen (benutzt BIG_ENDIAN_P !)    \
      }
  #elif defined(MC680X0) && !defined(MC680Y0)
    # Methode:
    # Sei x = x1*2^16+x0, y = y1*2^16+y0  mit
    # 0 <= x0,y0 < 2^16, 0 <= x1,y1 < 2^8 . Dann ist das Produkt x*y
    # >=0 und < 2^48. Es belegt also 3 16-Bit-Worte.
    # In  x * y = x1*y1*2^32 + (x1*y0+x0*y1)*2^16 + x0*y0
    # bestimmen die ersten beiden Summanden und das High-Word des dritten
    # Summanden die beiden höherwertigen Words des Ergebnisses (und
    # hierbei gibt es keinen Überlauf, da das Produkt in 3 Words paßt!),
    # das Low-Word des dritten Summanden ist auch das des Ergebnisses.
    #define mulu24(x,y,hi_zuweisung,lo_zuweisung)  \
      { var reg1 uint32 _x = (x);                                  \
        var reg2 uint32 _y = (y);                                  \
        var reg4 uint32 _erg21; # Teilresultat für Words 2 und 1 des Ergebnisses \
        var reg3 uint32 _erg10; # Teilresultat für Words 1 und 0 des Ergebnisses \
        { var reg3 uint16 _x1 = high16(_x);                        \
          var reg4 uint16 _y1 = high16(_y);                        \
          _erg21 = highlow32_0(mulu16(_x1,_y1))                    \
                  + mulu16(_x1,low16(_y)) + mulu16(low16(_x),_y1); \
        }                                                          \
        _erg10 = mulu16(low16(_x),low16(_y));                      \
        # Teilresultate kombinieren:                               \
        _erg21 += high16(_erg10);                                  \
        hi_zuweisung high16(_erg21);                               \
        lo_zuweisung highlow32(low16(_erg21),low16(_erg10));       \
      }
  #else
    #define mulu24  mulu32
  #endif

# Multipliziert zwei 32-Bit-Zahlen miteinander und liefert eine 64-Bit-Zahl:
# mulu32(arg1,arg2,hi=,lo=);
# > arg1, arg2 : zwei 32-Bit-Zahlen
# < 2^32*hi+lo : eine 64-Bit-Zahl
  extern uint32 mulu32_ (uint32 arg1, uint32 arg2); # -> Low-Teil
  extern uint32 mulu32_high;                        # -> High-Teil
# in 68000-Assembler (Input D0.L,D1.L, Output D0.L,D1.L, verändert D2-D4):
#   ; D0.L = 2^16*a+b, D1.L = 2^16*c+d -> Produkt
#   ; (2^16*a+b)*(2^16*c+d) = 2^32*a*c + 2^16*(a*d+b*c) + b*d
#   MOVE.L D0,D2 ! SWAP D2
#   MOVE.L D1,D3 ! SWAP D1
#   MOVE.L D1,D4 ! MULU D2,D1 ; a*c
#   MULU D3,D2 ; a*d
#   MULU D0,D4 ; b*c
#   MULU D3,D0 ; b*d
#   CLR.L D3 ; Hilfsregister für Zero-Extend
#   SWAP D2 ! MOVE.W D2,D3 ! ADD.L D3,D1 ; high16(a*d) zu D1.L addieren
#   SWAP D4 ! MOVE.W D4,D3 ! ADD.L D3,D1 ; high16(b*c) zu D1.L addieren
#   CLR.W D2 ! ADD.L D2,D0 ! BCC.S \1 ! ADDQ.L #1,D1 ! \1: ; 2^16*low16(a*d) zu D0.L addieren
#   CLR.W D4 ! ADD.L D4,D0 ! BCC.S \2 ! ADDQ.L #1,D1 ! \2: ; 2^16*low16(b*c) zu D0.L addieren
#   ; D0.L = lo, D1.L = hi fertig.
# in 68020-Assembler (Input D0.L,D1.L, Output D0.L,D1.L):
#   MULU.L D1,D1:D0
  #ifdef GNU
    #ifdef MC680X0
      #if !(defined(MC680Y0) && !defined(NO_ASM))
        #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
          ({ var reg4 uint32 _x = (x);                                      \
             var reg4 uint32 _y = (y);                                      \
             var reg5 uint16 _x1 = high16(_x);                              \
             var reg5 uint16 _x0 = low16(_x);                               \
             var reg5 uint16 _y1 = high16(_y);                              \
             var reg5 uint16 _y0 = low16(_y);                               \
             var reg3 uint32 _hi = mulu16(_x1,_y1); # obere Portion         \
             var reg2 uint32 _lo = mulu16(_x0,_y0); # untere Portion        \
             {var reg1 uint32 _mid = mulu16(_x0,_y1); # 1. mittlere Portion \
              _hi += high16(_mid); _mid = highlow32_0(low16(_mid));         \
              _lo += _mid; if (_lo < _mid) { _hi += 1; } # 64-Bit-Addition  \
             }                                                              \
             {var reg1 uint32 _mid = mulu16(_x1,_y0); # 2. mittlere Portion \
              _hi += high16(_mid); _mid = highlow32_0(low16(_mid));         \
              _lo += _mid; if (_lo < _mid) { _hi += 1; } # 64-Bit-Addition  \
             }                                                              \
             hi_zuweisung _hi;                                              \
             lo_zuweisung _lo;                                              \
           })
      #else
        #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
          ({ var reg3 uint32 _x = (x); \
             var reg4 uint32 _y = (y); \
             var reg2 uint32 _hi;      \
             var reg1 uint32 _lo;      \
             __asm__("mulul %3,%0:%1" : "=d" (_hi), "=d"(_lo) : "1" (_x), "dm" (_y) ); \
             hi_zuweisung _hi;         \
             lo_zuweisung _lo;         \
           })
      #endif
    #elif defined(SPARC)
      #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
        ({ lo_zuweisung mulu32_(x,y); # extern in Assembler \
          {var register uint32 _hi __asm__("%g1");          \
           hi_zuweisung _hi;                                \
         }})
    #elif defined(ARM)
      #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
        ({ lo_zuweisung mulu32_(x,y); # extern in Assembler \
          {var register uint32 _hi __asm__("%a2");          \
           hi_zuweisung _hi;                                \
         }})
    #elif defined(I80Z86) && !defined(NO_ASM)
      #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
        ({ var register uint32 _hi;                                  \
           var register uint32 _lo;                                  \
           __asm__("mull %2"                                         \
                   : "=d" /* %edx */ (_hi), "=a" /* %eax */ (_lo)    \
                   : "g" ((uint32)(x)), "1" /* %eax */ ((uint32)(y)) \
                  );                                                 \
           hi_zuweisung _hi; lo_zuweisung _lo;                       \
         })
    #elif defined(MIPS) && !defined(NO_ASM)
      #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
        ({ var register uint32 _hi;                       \
           var register uint32 _lo;                       \
           __asm__("multu %3,%2 ; mfhi %0 ; mflo %1"      \
                   : "=r" (_hi), "=r" (_lo)               \
                   : "r" ((uint32)(x)), "r" ((uint32)(y)) \
                  );                                      \
           hi_zuweisung _hi; lo_zuweisung _lo;            \
         })
    #elif defined(HAVE_LONGLONG)
      #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
        ({ var register uint64 _prod = (uint64)(x) * (uint64)(y); \
           hi_zuweisung (uint32)(_prod>>32);                      \
           lo_zuweisung (uint32)(_prod);                          \
         })
    #endif
  #endif
  #if defined(WATCOM) && defined(I80Z86) && !defined(NO_ASM)
    #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
      { var register uint32 _hi;                  \
        var register uint32 _lo;                  \
        _lo = mulu32_(x,y), _hi = mulu32_high_(); \
        hi_zuweisung _hi; lo_zuweisung _lo;       \
      }
    extern uint32 mulu32_high_ (void);
    #pragma aux mulu32_ = 0xF7 0xE2 /* mull %edx */ parm [eax] [edx] value [eax] modify [eax edx];
    #pragma aux mulu32_high_ = /* */ value [edx] modify [];
  #endif
  #ifndef mulu32
    #define mulu32(x,y,hi_zuweisung,lo_zuweisung)  \
      (lo_zuweisung mulu32_(x,y), hi_zuweisung mulu32_high)
    #if defined(MC680X0) || defined(SPARC) || defined(ARM) || (defined(I80Z86) && !defined(WATCOM)) || defined(MIPS) || defined(HPPA) || defined(VAX)
      # mulu32_ extern in Assembler
      #if defined(SPARC)
        #define mulu32_high  (uint32)(_get_g1()) # Rückgabe im Register %g1
      #elif defined(LISPARIT) && !defined(HPPA) # In arihppa.d ist mulu32_high bereits definiert.
        global uint32 mulu32_high;
      #endif
    #else
      #ifdef LISPARIT
      global uint32 mulu32_high;
      global uint32 mulu32_(x,y)
        var reg4 uint32 x;
        var reg4 uint32 y;
        { var reg5 uint16 x1 = high16(x);
          var reg5 uint16 x0 = low16(x);
          var reg5 uint16 y1 = high16(y);
          var reg5 uint16 y0 = low16(y);
          var reg3 uint32 hi = mulu16(x1,y1); # obere Portion
          var reg2 uint32 lo = mulu16(x0,y0); # untere Portion
          {var reg1 uint32 mid = mulu16(x0,y1); # 1. mittlere Portion
           hi += high16(mid); mid = highlow32_0(low16(mid));
           lo += mid; if (lo < mid) { hi += 1; } # 64-Bit-Addition
          }
          {var reg1 uint32 mid = mulu16(x1,y0); # 2. mittlere Portion
           hi += high16(mid); mid = highlow32_0(low16(mid));
           lo += mid; if (lo < mid) { hi += 1; } # 64-Bit-Addition
          }
          mulu32_high = hi; return lo;
        }
      #endif
    #endif
  #endif

# Multipliziert zwei 32-Bit-Zahlen miteinander und liefert eine 32-Bit-Zahl:
# mulu32_unchecked(arg1,arg2)
# > arg1, arg2 : zwei 32-Bit-Zahlen
# < ergebnis : eine 32-Bit-Zahl
# Es wird vorausgesetzt, daß arg1*arg2 < 2^32.
  #if (defined(GNU) && defined(MC680X0) && !defined(MC680Y0))
    extern uint32 mulu32_unchecked (uint32 x, uint32 y);
    #ifdef LISPARIT
    global uint32 mulu32_unchecked(x,y)
      var reg2 uint32 x;
      var reg3 uint32 y;
      { # Methode:
        # Falls x>=2^16 und y>=2^16 wäre, wäre das Produkt zu groß.
        # Falls x<2^16 : y = y1*2^16+y0 schreiben, (x*y1)*2^16 + (x*y0) bilden.
        # Falls y<2^16 : x = x1*2^16+x0 schreiben, (x1*y)*2^16 + (x0*y) bilden.
        # Falls sogar x<2^16 und y<2^16: nur x*y bilden.
        var reg4 uint16 x1 = high16(x);
        var reg5 uint16 y1 = high16(y);
        if (x1==0)
          if (y1==0)
            return mulu16((uint16)(x),(uint16)(y));
            else
            return highlow32_0(mulu16((uint16)(x),y1))
                   + mulu16((uint16)(x),low16(y));
          else
          return highlow32_0(mulu16(x1,(uint16)(y)))
                 + mulu16(low16(x),(uint16)(y));
      }
    #endif
  #elif defined(SPARC)
    extern uint32 mulu32_unchecked (uint32 x, uint32 y); # extern in Assembler
  #else
    # Wir können dafür auch die Bibliotheksroutine des C-Compilers nehmen:
    #define mulu32_unchecked(x,y)  ((uint32)((uint32)(x)*(uint32)(y)))
  #endif

# Dividiert eine 16-Bit-Zahl durch eine 16-Bit-Zahl und
# liefert einen 16-Bit-Quotienten und einen 16-Bit-Rest.
# divu_1616_1616(x,y,q=,r=);
# > uint16 x: Zähler
# > uint16 y: Nenner
# < uint16 q: floor(x/y)
# < uint16 r: x mod y
# < x = q*y+r
  #define divu_1616_1616(x,y,q_zuweisung,r_zuweisung)  \
    { var reg1 uint16 __x = (x);   \
      var reg2 uint16 __y = (y);   \
      q_zuweisung floor(__x,__y);  \
      r_zuweisung (__x % __y);     \
    }

# Dividiert eine 32-Bit-Zahl durch eine 16-Bit-Zahl und
# liefert einen 16-Bit-Quotienten und einen 16-Bit-Rest.
# divu_3216_1616(x,y,q=,r=);
# > uint32 x: Zähler
# > uint16 y: Nenner
# > Es sei bekannt, daß 0 <= x < 2^16*y .
# < uint16 q: floor(x/y)
# < uint16 r: x mod y
# < x = q*y+r
  extern uint16 divu_3216_1616_ (uint32 x, uint16 y); # -> Quotient q
  extern uint16 divu_16_rest;                         # -> Rest r
# im 68000-Assembler (Input D0.L,D1.W, Output D0.W,D1.W):
#   DIVU D1,D0    ; D0.L=x / D1.W=y -> q=D0.W, r=D0.H.W
#   MOVE.L D0,D1
#   SWAP D1
  #ifdef GNU
    #if defined(SPARC)
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        ({ var reg1 uint32 __qr = divu_3216_1616_(x,y); # extern in Assembler \
           q_zuweisung low16(__qr);  \
           r_zuweisung high16(__qr); \
         })
    #elif defined(MC680X0) && !defined(NO_ASM)
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        ({var uint32 __x = (x);      \
          var uint16 __y = (y);      \
          var uint32 __qr;           \
          __asm__ __volatile__ ("\
            divu %2,%0   \
            " : "=d" (__qr) : "0" (__x), "dm" (__y));  \
          q_zuweisung low16(__qr);   \
          r_zuweisung high16(__qr);  \
         })
    #elif defined(I80Z86) && !defined(NO_ASM)
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        ({var uint32 __x = (x);  \
          var uint16 __y = (y);  \
          var uint16 __q;        \
          var uint16 __r;        \
          __asm__("divw %4"      \
                  : "=a" /* %ax */ (__q), "=d" /* %dx */ (__r) \
                  : "1" /* %dx */ ((uint16)(high16(__x))), "0" /* %ax */ ((uint16)(low16(__x))), "rm" (__y) \
                 );              \
          q_zuweisung __q;       \
          r_zuweisung __r;       \
         })
    #else
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        ({var uint32 __x = (x);            \
          var uint16 __y = (y);            \
          var uint16 __q = floor(__x,__y); \
          q_zuweisung __q;                 \
          r_zuweisung (__x - __q * __y);   \
         })
    #endif
  #else
    #if defined(SPARC)
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        { var reg1 uint32 __qr = divu_3216_1616_(x,y); # extern in Assembler \
          q_zuweisung low16(__qr);  \
          r_zuweisung high16(__qr); \
        }
    #elif defined(ARM)
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        { q_zuweisung divu_3216_1616_(x,y); # extern in Assembler \
          r_zuweisung divu_16_rest;                               \
        }
      #ifdef LISPARIT
      global uint16 divu_16_rest;
      #endif
    #else
      #define divu_3216_1616(x,y,q_zuweisung,r_zuweisung)  \
        { q_zuweisung divu_3216_1616_(x,y); r_zuweisung divu_16_rest; }
      #ifdef LISPARIT
      global uint16 divu_16_rest;
      global uint16 divu_3216_1616_(x,y)
        var reg3 uint32 x;
        var reg2 uint16 y;
        { var reg1 uint16 q = floor(x,(uint32)y);
          divu_16_rest = x - (uint32)q * (uint32)y;
          return q;
        }
      #endif
    #endif
  #endif

# Dividiert eine 32-Bit-Zahl durch eine 16-Bit-Zahl und
# liefert einen 32-Bit-Quotienten und einen 16-Bit-Rest.
# divu_3216_3216(x,y,q=,r=);
# > uint32 x: Zähler
# > uint16 y: Nenner
# Es sei bekannt, daß y>0.
# < uint32 q: floor(x/y)
# < uint16 r: x mod y
# < x = q*y+r
  extern uint32 divu_3216_3216_ (uint32 x, uint16 y); # -> Quotient q
  extern uint16 divu_16_rest;                         # -> Rest r
# im 68000-Assembler (Input D0.L,D1.W, Output D0.L,D1.W, verändert D2,D3):
#   MOVE.L D0,D2
#   CLR.W D2
#   SWAP D2        ; D2.L = D2.W := D0.H.W = high16(x)
#   DIVU D1,D2     ; durch y dividieren
#   MOVE.W D2,D3   ; Quotient nach D3.W
#   MOVE.W D0,D2   ; Rest (in D2.H.W) mit D0.W = low16(x) kombinieren
#   DIVU D1,D2     ; und wieder durch y dividieren
#   MOVE.W D3,D0   ; ersten Quotiententeil
#   SWAP D0        ; mal 2^16
#   MOVE.W D2,D0   ; plus zweiten Quotiententeil, liefert q
#   SWAP D2
#   MOVE.W D2,D1   ; r = Rest der zweiten Division
# oder (Input D0.L,D1.W, Output D0.L,D1.W, verändert D2,D3):
#   MOVE.L D0,D2   ; x retten
#   CLR.W D0
#   SWAP D0        ; D0.L = D0.W := high16(x)
#   DIVU D1,D0     ; durch y dividieren
#   MOVE.W D0,D3   ; Quotient nach D3.W
#   MOVE.W D2,D0   ; Rest (in D0.H.W) mit D2.W = low16(x) kombinieren
#   DIVU D1,D0     ; und wieder durch y dividieren
#   SWAP D0
#   MOVE.W D0,D1   ; r = Rest der zweiten Division
#   MOVE.W D3,D0
#   SWAP D0        ; beide Quotienten kombinieren, liefert q
  #if defined(SPARC) || defined(I80Z86)
    #define divu_3216_3216  divu_3232_3232
  #elif 1
    # Methode: (beta = 2^16)
    # x = x1*beta+x0 schreiben.
    # Division mit Rest: x1 = q1*y + r1, wobei 0 <= x1 < beta <= beta*y.
    # Also 0 <= q1 < beta, 0 <= r1 < y.
    # Division mit Rest: (r1*beta+x0) = q0*y + r0, wobei 0 <= r1*beta+x0 < beta*y.
    # Also 0 <= q0 < beta, 0 <= r0 < y
    # und x = x1*beta+x0 = (q1*beta+q0)*y + r0.
    # Setze q := q1*beta+q0 und r := r0.
    #ifdef GNU
      #define divu_3216_3216(x,y,q_zuweisung,r_zuweisung)  \
        ({var uint32 _x = (x);     \
          var uint16 _y = (y);     \
          var uint16 _q1;          \
          var uint16 _q0;          \
          var uint16 _r1;          \
          divu_3216_1616(high16(_x),_y, _q1 = , _r1 = ); \
          divu_3216_1616(highlow32(_r1,low16(_x)),_y, _q0 = , _EMA_ r_zuweisung); \
          q_zuweisung highlow32(_q1,_q0);  \
         })
    #else
      #define divu_3216_3216(x,y,q_zuweisung,r_zuweisung)  \
        {var reg1 uint32 _x = (x);     \
         var reg2 uint16 _y = (y);     \
         var reg3 uint16 _q1;          \
         var reg4 uint16 _q0;          \
         var reg5 uint16 _r1;          \
         divu_3216_1616(high16(_x),_y, _q1 = , _r1 = ); \
         divu_3216_1616(highlow32(_r1,low16(_x)),_y, _q0 = , _EMA_ r_zuweisung); \
         q_zuweisung highlow32(_q1,_q0);  \
        }
    #endif
  #else
    #define divu_3216_3216(x,y,q_zuweisung,r_zuweisung)  \
      { q_zuweisung divu_3216_3216_(x,y); r_zuweisung divu_16_rest; }
    #if 0
      # divu_3216_3216_ extern in Assembler
    #else
      #ifdef LISPARIT
      global uint32 divu_3216_3216_(x,y)
        var reg1 uint32 x;
        var reg2 uint16 y;
        { var reg4 uint16 q1;
          var reg5 uint16 q0;
          var reg3 uint16 r1;
          divu_3216_1616(high16(x),y, q1 = , r1 = );
          divu_3216_1616(highlow32(r1,low16(x)),y, q0 = , divu_16_rest =);
          return highlow32(q1,q0);
        }
      #endif
    #endif
  #endif

# Dividiert eine 32-Bit-Zahl durch eine 32-Bit-Zahl und
# liefert einen 32-Bit-Quotienten und einen 32-Bit-Rest.
# divu_3232_3232(x,y,q=,r=);
# > uint32 x: Zähler
# > uint32 y: Nenner
# Es sei bekannt, daß y>0.
# < uint32 q: floor(x/y)
# < uint32 r: x mod y
# < x = q*y+r
  extern uint32 divu_3232_3232_ (uint32 x, uint32 y); # -> Quotient q
  extern uint32 divu_32_rest;                         # -> Rest r
  #if defined(SPARC) || defined(I80Z86) || defined(HPPA_DIV_WORKS)
    #define divu_3232_3232(x,y,q_zuweisung,r_zuweisung)  \
      divu_6432_3232(0,x,y,q_zuweisung,_EMA_ r_zuweisung)
    #define divu_3232_3232_(x,y) divu_6432_3232_(0,x,y)
  #elif 1
    # Methode: (beta = 2^n = 2^16, n = 16)
    # Falls y < beta, handelt es sich um eine 32-durch-16-Bit-Division.
    # Falls y >= beta:
    # Quotient  q = floor(x/y) < beta  (da 0 <= x < beta^2, y >= beta).
    # y habe genau n+k Bits (1 <= k <= n), d.h. 2^(n+k-1) <= y < 2^(n+k).
    # Schreibe  x = 2^k*x1 + x0  mit  x1 := floor(x/2^k)
    # und       y = 2^k*y1 + y0  mit  y1 := floor(y/2^k)
    # und bilde den Näherungs-Quotienten floor(x1/y1)
    # oder (noch besser) floor(x1/(y1+1)).
    # Wegen 0 <= x1 < 2^(2n) und 0 < 2^(n-1) <= y1 < 2^n
    # und  x1/(y1+1) <= x/y < x1/(y1+1) + 2
    # (denn x1/(y1+1) = (x1*2^k)/((y1+1)*2^k) <= (x1*2^k)/y <= x/y
    # und x/y - x1/(y1+1) = (x+x*y1-x1*y)/(y*(y1+1))
    # = (x+x0*y1-x1*y0)/(y*(y1+1)) <= (x+x0*y1)/(y*(y1+1))
    # <= x/(y*(y1+1)) + x0/y
    # <= 2^(2n)/(2^(n+k-1)*(2^(n-1)+1)) + 2^k/2^(n+k-1)
    # = 2^(n-k+1)/(2^(n-1)+1) + 2^(1-n) <= 2^n/(2^(n-1)+1) + 2^(1-n) < 2 )
    # gilt  floor(x1/(y1+1)) <= floor(x/y) <= floor(x1/(y1+1)) + 2  .
    # Man bildet also  q:=floor(x1/(y1+1))  (ein Shift um n Bit oder
    # eine (2n)-durch-n-Bit-Division, mit Ergebnis q <= floor(x/y) < beta)
    # und x-q*y und muß hiervon noch höchstens 2 mal y abziehen und q
    # incrementieren, um den Quotienten  q = floor(x/y)  und den Rest
    # x-floor(x/y)*y  der Division zu bekommen.
    #define divu_3232_3232(x,y,q_zuweisung,r_zuweisung)  \
      { var uint32 _x = (x);                                                    \
        var uint32 _y = (y);                                                    \
        if (_y <= (uint32)(bit(16)-1))                                          \
          { var uint16 _q1;                                                     \
            var uint16 _q0;                                                     \
            var uint16 _r1;                                                     \
            divu_3216_1616(high16(_x),_y, _q1 = , _r1 = );                      \
            divu_3216_1616(highlow32(_r1,low16(_x)),_y, _q0 = , _EMA_ r_zuweisung); \
            q_zuweisung highlow32(_q1,_q0);                                     \
          }                                                                     \
          else                                                                  \
          { var uint32 _x1 = _x; # x1 := x                                      \
            var uint32 _y1 = _y; # y1 := y                                      \
            var uint16 _q;                                                      \
            do { _x1 = floor(_x1,2); _y1 = floor(_y1,2); } # k erhöhen          \
               until (_y1 <= (uint32)(bit(16)-1)); # bis y1 < beta              \
            { var uint16 _y2 = low16(_y1)+1; # y1+1 bilden                      \
              if (_y2==0)                                                       \
                { _q = high16(_x1); } # y1+1=beta -> ein Shift                  \
                else                                                            \
                { divu_3216_1616(_x1,_y2,_q=,); } # Division von x1 durch y1+1  \
            }                                                                   \
            # _q = q = floor(x1/(y1+1))                                         \
            # x-q*y bilden (eine 16-mal-32-Bit-Multiplikation ohne Überlauf):   \
            _x -= highlow32_0(mulu16(_q,high16(_y))); # q * high16(y) * beta    \
            # gefahrlos, da q*high16(y) <= q*y/beta <= x/beta < beta            \
            _x -= mulu16(_q,low16(_y)); # q * low16(y)                          \
            # gefahrlos, da q*high16(y)*beta + q*low16(y) = q*y <= x            \
            # Noch höchstens 2 mal y abziehen:                                  \
            if (_x >= _y)                                                       \
              { _q += 1; _x -= _y;                                              \
                if (_x >= _y)                                                   \
                  { _q += 1; _x -= _y;                                          \
              }   }                                                             \
            r_zuweisung _x;                                                     \
            q_zuweisung (uint32)(_q);                                           \
      }   }
    #ifdef LISPARIT
    # Dies dient nur noch als Hilfsfunktion für arilev1.d.
    # Die Rückgabe des Restes in divu_32_rest ist also hier nicht nötig.
    global uint32 divu_3232_3232_(x,y)
      var reg2 uint32 x;
      var reg1 uint32 y;
      { var reg3 uint32 q;
        divu_3232_3232(x,y,q=,);
        return q;
      }
    #endif
  #else
    #define divu_3232_3232(x,y,q_zuweisung,r_zuweisung)  \
      { q_zuweisung divu_3232_3232_(x,y); r_zuweisung divu_32_rest; }
    #if 0
      # divu_3232_3232_ extern in Assembler
    #else
      #ifdef LISPARIT
      global uint32 divu_3232_3232_(x,y)
        var reg2 uint32 x;
        var reg1 uint32 y;
        { var reg3 uint32 q = floor(x,y);
          divu_32_rest = x - q*y;
          return q;
        }
      #endif
    #endif
  #endif

# Dividiert eine 64-Bit-Zahl durch eine 32-Bit-Zahl und
# liefert einen 32-Bit-Quotienten und einen 32-Bit-Rest.
# divu_6432_3232(xhi,xlo,y,q=,r=);
# > uint32 xhi,xlo: x = 2^32*xhi+xlo = Zähler
# > uint32 y: Nenner
# > Es sei bekannt, daß 0 <= x < 2^32*y .
# < uint32 q: floor(x/y)
# < uint32 r: x mod y
# < x = q*y+r
  extern uint32 divu_6432_3232_ (uint32 xhi, uint32 xlo, uint32 y); # -> Quotient q
  extern uint32 divu_32_rest;                                       # -> Rest r
  #ifdef GNU
    #if defined(MC680Y0) && !defined(NO_ASM)
      #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung)  \
        ({var uint32 __xhi = (xhi);  \
          var uint32 __xlo = (xlo);  \
          var uint32 __y = (y);      \
          var uint32 __q;            \
          var uint32 __r;            \
          __asm__ __volatile__ ("\
            divul %4,%1:%0   \
            " : "=d" (__q), "=d" (__r) : "1" (__xhi), "0" (__xlo), "dm" (__y));  \
          q_zuweisung __q;           \
          r_zuweisung __r;           \
         })
      #define divu_6432_3232_(xhi,xlo,y) \
        ({var reg1 uint32 ___q; divu_6432_3232(xhi,xlo,y,___q=,); ___q; })
    #elif defined(SPARC)
      #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung)  \
        ({ var reg1 uint32 _q = divu_6432_3232_(xhi,xlo,y); # extern in Assembler \
           var register uint32 _r __asm__("%g1");                                 \
           q_zuweisung _q; r_zuweisung _r;                                        \
         })
    #elif defined(ARM)
      #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung)  \
        ({ var reg1 uint32 _q = divu_6432_3232_(xhi,xlo,y); # extern in Assembler \
           var register uint32 _r __asm__("%a2");                                 \
           q_zuweisung _q; r_zuweisung _r;                                        \
         })
    #elif defined(I80Z86) && !defined(NO_ASM)
      #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung)  \
        ({var uint32 __xhi = (xhi);  \
          var uint32 __xlo = (xlo);  \
          var uint32 __y = (y);      \
          var uint32 __q;            \
          var uint32 __r;            \
          __asm__ __volatile__ (     \
             "divl %4"               \
             : "=a" /* %eax */ (__q), "=d" /* %edx */ (__r)               \
             : "1" /* %edx */ (__xhi), "0" /* %eax */ (__xlo), "rm" (__y) \
             );                      \
          q_zuweisung __q;           \
          r_zuweisung __r;           \
         })
      #define divu_6432_3232_(xhi,xlo,y) \
        ({var reg1 uint32 ___q; divu_6432_3232(xhi,xlo,y,___q=,); ___q; })
    #elif defined(HAVE_LONGLONG) && !defined(HPPA_DIV_WORKS)
      #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung) \
        ({var reg1 uint32 __xhi = (xhi);                           \
          var reg1 uint32 __xlo = (xlo);                           \
          var reg1 uint64 __x = (uint64)__xhi<<32 | (uint64)__xlo; \
          var reg1 uint32 __y = (y);                               \
          var reg1 uint32 __q = floor(__x,(uint64)__y);            \
          q_zuweisung __q; r_zuweisung __xlo - __q * __y;          \
         })
      #define divu_6432_3232_(xhi,xlo,y) \
        ({var reg1 uint32 ___q; divu_6432_3232(xhi,xlo,y,___q=,); ___q; })
    #endif
  #endif
  #if defined(WATCOM) && defined(I80Z86) && !defined(NO_ASM)
    #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung)  \
      { var uint32 __xhi = (xhi);  \
        var uint32 __xlo = (xlo);  \
        var uint32 __y = (y);      \
        var uint32 __q;            \
        var uint32 __r;            \
        __q = divu_6432_3232_(__xhi,__xlo,__y); __r = divu_6432_3232_rest(); \
        q_zuweisung __q;           \
        r_zuweisung __r;           \
      }
    extern uint32 divu_6432_3232_rest (void);
    #pragma aux divu_6432_3232_ = 0xF7 0xF1 /* divl %ecx */ parm [edx] [eax] [ecx] value [eax] modify [eax edx];
    #pragma aux divu_6432_3232_rest = /* */ value [edx] modify [];
  #endif
  #ifndef divu_6432_3232
    #define divu_6432_3232(xhi,xlo,y,q_zuweisung,r_zuweisung)  \
      { q_zuweisung divu_6432_3232_(xhi,xlo,y); r_zuweisung divu_32_rest; }
    #if defined(MC680Y0) || defined(SPARC) || defined(ARM) || (defined(I80Z86) && !defined(WATCOM)) || defined(HPPA)
      # divu_6432_3232_ extern in Assembler
      #if defined(SPARC)
        #define divu_32_rest  (uint32)(_get_g1()) # Rückgabe im Register %g1
      #elif defined(LISPARIT)
        global uint32 divu_32_rest;
      #endif
    #else
      #ifdef LISPARIT
      # Methode:
      # Wie UDS_divide mit intDsize=16, a_len=4, b_len=2.
      global uint32 divu_32_rest;
      global uint32 divu_6432_3232_(xhi,xlo,y)
        var reg9 uint32 xhi;
        var reg6 uint32 xlo;
        var reg1 uint32 y;
        { if (y <= (uint32)(bit(16)-1))
            # 48-durch-16-Bit-Division,
            # aufgebaut aus zwei 32-durch-16-Bit-Divisionen:
            { var reg4 uint16 q1;
              var reg3 uint16 q0;
              var reg2 uint16 r1;
              divu_3216_1616(highlow32(low16(xhi),high16(xlo)),y, q1=,r1=);
              divu_3216_1616(highlow32(r1,low16(xlo)),y, q0=, divu_32_rest=(uint32) );
              return highlow32(q1,q0);
            }
          # y>=2^16
         {# y shiften:
          var reg10 uintL s = 0;
          while ((sint32)y >= 0) { y = y<<1; s++; }
          # x entsprechend shiften:
          if (!(s==0))
            { xhi = (xhi << s) | (xlo >> (32-s)); xlo = xlo << s; }
          # 64-durch-32-Bit-Division,
          # aufgebaut aus zwei 48-durch-32-Bit-Divisionen.
          # Methode für eine 48-durch-32-Bit-Division x/y mit 0 <= x < 2^16*y :
          # (beta = 2^n = 2^16, n = 16)
          # Wir wissen beta^2/2 <= y < beta^2, Quotient  q = floor(x/y) < beta.
          # Schreibe  x = beta*x1 + x0  mit  x1 := floor(x/beta)
          # und       y = beta*y1 + y0  mit  y1 := floor(y/beta)
          # und bilde den Näherungs-Quotienten floor(x1/y1)
          # oder (noch besser) floor(x1/(y1+1)).
          # Wegen 0 <= x1 < 2^(2n) und 0 < 2^(n-1) <= y1 < 2^n
          # und  x1/(y1+1) <= x/y < x1/(y1+1) + 2
          # (denn x1/(y1+1) = (x1*beta)/((y1+1)*beta) <= (x1*beta)/y <= x/y
          # und x/y - x1/(y1+1) = (x+x*y1-x1*y)/(y*(y1+1))
          # = (x+x0*y1-x1*y0)/(y*(y1+1)) <= (x+x0*y1)/(y*(y1+1))
          # <= x/(y*(y1+1)) + x0/y = (x/y)/(y1+1) + x0/y
          # <= 2^n/(2^(n-1)+1) + 2^n/2^(2n-1) = 2^n/(2^(n-1)+1) + 2^(1-n) < 2 )
          # gilt  floor(x1/(y1+1)) <= floor(x/y) <= floor(x1/(y1+1)) + 2  .
          # Man bildet also  q:=floor(x1/(y1+1))  (ein Shift um n Bit oder
          # eine (2n)-durch-n-Bit-Division, mit Ergebnis q <= floor(x/y) < beta)
          # und x-q*y und muß hiervon noch höchstens 2 mal y abziehen und q
          # incrementieren, um den Quotienten  q = floor(x/y)  und den Rest
          # x-floor(x/y)*y  der Division zu bekommen.
          { var reg2 uint16 y1_1 = high16(y)+1; # y1+1
            var reg7 uint16 q1;
            var reg8 uint16 q0;
            var reg3 uint32 r;
            # 2^16*xhi+high16(xlo) durch y dividieren:
           {var reg5 uint16 r16;
            var reg4 uint32 r2;
            if (y1_1==0)
              { q1 = high16(xhi); r16 = low16(xhi); }
              else
              { divu_3216_1616(xhi,y1_1, q1=,r16=); }
            # q1 = floor(xhi/(y1+1)), r16 = xhi - (y1+1)*q1 (>=0, <=y1)
            # Bilde r := (2^16*xhi+high16(xlo)) - y*q1
            #          = 2^16*(xhi-y1*q1) + high16(xlo) - y0*q1
            #          = 2^16*r16 + 2^16*q1 + high16(xlo) - y0*q1 (>=0)
            # Dies ist < 2^16*y1 + 2^32 <= y + 2^32 <= 3*y, kann überlaufen!
            r = highlow32(r16,high16(xlo)); # 2^16*r16 + high16(xlo) < 2^32
            r2 = highlow32_0(q1) - mulu16(low16(y),q1); # 2^16*q1 - y0*q1 < 2^32
            # 0 <= r+r2 < 3*y. Bei der Addition auf Carry testen!
            # Carry -> jedenfalls y <= r+r2 < y + 2^32 <= 3*y.
            # kein Carry -> jedenfalls 0 <= r+r2 < 2^32 <= 2*y.
            if ((r += r2) < r2) # addieren, r >= 2^32 ?
              { q1 += 1; r -= y; }
            # jetzt noch 0 <= r < 2^32 <= 2*y
            if (r >= y)
              { q1 += 1; r -= y; }
           }# Quotient q1, Rest r fertig.
            # 2^16*r+low16(xlo) durch y dividieren:
           {var reg5 uint16 r16;
            var reg4 uint32 r2;
            if (y1_1==0)
              { q0 = high16(r); r16 = low16(r); }
              else
              { divu_3216_1616(r,y1_1, q0=,r16=); }
            # q0 = floor(r/(y1+1)), r16 = r - (y1+1)*q0 (>=0, <=y1)
            # Bilde r := (2^16*r+low16(xlo)) - y*q0
            #          = 2^16*(r-y1*q0) + low16(xlo) - y0*q0
            #          = 2^16*r16 + 2^16*q0 + low16(xlo) - y0*q0 (>=0)
            # Dies ist < 2^16*y1 + 2^32 <= y + 2^32 <= 3*y, kann überlaufen!
            r = highlow32(r16,low16(xlo)); # 2^16*r16 + low16(xlo) < 2^32
            r2 = highlow32_0(q0) - mulu16(low16(y),q0); # 2^16*q0 - y0*q0 < 2^32
            # 0 <= r+r2 < 3*y. Bei der Addition auf Carry testen!
            # Carry -> jedenfalls y <= r+r2 < y + 2^32 <= 3*y.
            # kein Carry -> jedenfalls 0 <= r+r2 < 2^32 <= 2*y.
            if ((r += r2) < r2) # addieren, r >= 2^32 ?
              { q0 += 1; r -= y; }
            # jetzt noch 0 <= r < 2^32 <= 2*y
            if (r >= y)
              { q0 += 1; r -= y; }
           }# Quotient q0, Rest r fertig.
            divu_32_rest = r >> s; # Rest
            return highlow32(q1,q0); # Quotient
        }}}
      #endif
    #endif
  #endif

# Zieht die Ganzzahl-Wurzel aus einer 32-Bit-Zahl und
# liefert eine 16-Bit-Wurzel und einen Rest.
# isqrt_32_16(x,y=,sqrtp=);
# > uint32 x: Radikand, >= 2^30, < 2^32
# < uint16 y: floor(sqrt(x)), >= 2^15, < 2^16
# < boolean sqrtp: /=0, falls x=y^2
  # Methode:
  # y := 2^16 als Anfangswert,
  # y := floor((y + floor(x/y))/2) als nächster Wert,
  # solange z := floor(x/y) < y, setze y := floor((y+z)/2).
  # y ist fertig; x=y^2 genau dann, wenn z=y und die letzte Division aufging.
  # (Beweis:
  #  1. Die Folge der y ist streng monoton fallend.
  #  2. Stets gilt y >= floor(sqrt(x)) (denn für alle y>0 ist
  #     y + x/y >= 2*sqrt(x) und daher  floor((y + floor(x/y))/2) =
  #     floor(y/2 + x/(2*y)) >= floor(sqrt(x)) ).
  #  3. Am Schluß gilt x >= y^2.
  # )
  #define isqrt_32_16(x,y_zuweisung,sqrtp_zuweisung)  \
    { var reg4 uint32 _x = (x);                                        \
      var reg3 uint16 _x1 = high16(_x);                                \
      var reg1 uint16 _y = floor(_x1,2) | bit(16-1);                   \
      loop                                                             \
        { var reg2 uint16 _z;                                          \
          var reg5 uint16 _r;                                          \
          if (_x1 >= _y) # Division _x/_y ergäbe Überlauf -> _z > _y   \
            { nowarn sqrtp_zuweisung FALSE; break; }                   \
          divu_3216_1616(_x,_y, _z=,_r=); # Dividiere _x/_y            \
          if (_z >= _y)                                                \
            { nowarn sqrtp_zuweisung (_z == _y) && (_r == 0); break; } \
          _y = floor((uint16)(_z+_y),2) | bit(16-1); # _y muß >= 2^15 bleiben  \
        }                                                              \
      y_zuweisung _y;                                                  \
    }

# Zieht die Ganzzahl-Wurzel aus einer 64-Bit-Zahl und
# liefert eine 32-Bit-Wurzel und einen Rest.
# isqrt_64_32(xhi,xlo,y=,sqrtp=);
# > uint32 xhi,xlo: Radikand x = 2^32*xhi+xlo, >= 2^62, < 2^64
# < uint32 y: floor(sqrt(x)), >= 2^31, < 2^32
# < boolean sqrtp: /=0, falls x=y^2
  #if (defined(SPARC) || defined(MC680Y0) || defined(HPPA))
    # Methode:
    # y := 2^32 als Anfangswert,
    # y := floor((y + floor(x/y))/2) als nächster Wert,
    # solange z := floor(x/y) < y, setze y := floor((y+z)/2).
    # y ist fertig; x=y^2 genau dann, wenn z=y und die letzte Division aufging.
    # (Beweis:
    #  1. Die Folge der y ist streng monoton fallend.
    #  2. Stets gilt y >= floor(sqrt(x)) (denn für alle y>0 ist
    #     y + x/y >= 2*sqrt(x) und daher  floor((y + floor(x/y))/2) =
    #     floor(y/2 + x/(2*y)) >= floor(sqrt(x)) ).
    #  3. Am Schluß gilt x >= y^2.
    # )
    #define isqrt_64_32(xhi,xlo,y_zuweisung,sqrtp_zuweisung)  \
      { var reg3 uint32 _xhi = (xhi);                                   \
        var reg4 uint32 _xlo = (xlo);                                   \
        var reg1 uint32 _y = floor(_xhi,2) | bit(32-1);                 \
        loop                                                            \
          { var reg2 uint32 _z;                                         \
            var reg5 uint32 _rest;                                      \
            if (_xhi >= _y) # Division _x/_y ergäbe Überlauf -> _z > _y \
              { sqrtp_zuweisung FALSE; break; }                         \
            divu_6432_3232(_xhi,_xlo,_y, _z=,_rest=); # Dividiere _x/_y \
            if (_z >= _y)                                               \
              { sqrtp_zuweisung (_z == _y) && (_rest == 0); break; }    \
            _y = floor(_z+_y,2) | bit(32-1); # _y muß >= 2^31 bleiben   \
          }                                                             \
        y_zuweisung _y;                                                 \
      }
  #else
    # Methode:
    # Wie bei UDS_sqrt mit n=2.
    # y = 2^16*yhi + ylo ansetzen.
    # Dann muß
    #   yhi = floor(y/2^16) = floor(floor(sqrt(x))/2^16)
    #       = floor(sqrt(x)/2^16) = floor(sqrt(x/2^32)) = isqrt(xhi)
    # sein. Es folgt yhi >= 2^15.
    # Danach sucht man das größte ylo >=0 mit
    # x - 2^32*yhi^2 >= 2*2^16*yhi*ylo + ylo^2.
    # Dazu setzen wir  xhi*2^32+xlo := x - 2^32*yhi^2
    # (also xhi := xhi - yhi^2, das ist >=0, <=2*yhi).
    # Die Schätzung für die zweite Ziffer
    #     ylo' := min(2^16-1,floor((xhi*2^32+xlo)/(2*2^16*yhi)))
    # erfüllt ylo'-1 <= ylo <= ylo', ist also um höchstens 1 zu groß.
    # (Beweis: Rechte Ungleichung klar, da  ylo < 2^16  und
    #   xhi*2^32+xlo >= 2*2^16*yhi*ylo + ylo^2 >= 2*2^16*yhi*ylo
    #   ==> (xhi*2^32+xlo)/(2*2^16*yhi) >= ylo  gelten muß.
    #   Linke Ungleichung: Falls floor(...)>=2^16, ist
    #   xhi*2^32+xlo >= 2*2^16*2^16*yhi >= 2*2^16*yhi*(2^16-1) + 2^32
    #                >= 2*2^16*yhi*(2^16-1) + (2^16-1)^2
    #   und xhi*2^32+xlo < 2*2^16*2^16*yhi + (2^16)^2, also
    #   ylo = 2^16-1 = ylo'.
    #   Sonst ist ylo' = floor((xhi*2^32+xlo)/(2*2^16*yhi)), also
    #   xhi*2^32+xlo >= 2*2^16*yhi*ylo' >= 2*2^16*yhi*(ylo'-1) + 2^32
    #                >= 2*2^16*yhi*(ylo'-1) + (ylo'-1)^2,
    #   also ylo >= ylo'-1 nach Definition von ylo.)
    #define isqrt_64_32(xhi,xlo,y_zuweisung,sqrtp_zuweisung)  \
      { var reg4 uint32 _xhi = (xhi);                                        \
        var reg3 uint32 _xlo = (xlo);                                        \
        var reg6 uint16 _yhi;                                                \
        var reg5 uint16 _ylo;                                                \
        # erste Ziffer berechnen:                                            \
        isqrt_32_16(_xhi,_yhi=,); # yhi := isqrt(xhi)                        \
        _xhi -= mulu16(_yhi,_yhi); # jetzt 0 <= xhi <= 2*yhi                 \
        # x = 2^32*yhi^2 + 2^32*xhi + xlo                                    \
        # Schätzung für die zweite Ziffer berechnen:                         \
        # ylo := min(2^16-1,floor((xhi*2^32+xlo)/(2*2^16*yhi))) bilden:      \
       {var reg1 uint32 _z = (_xhi << 15) | (_xlo >> 17); # < 2^15*(2*yhi+1) \
        var reg2 uint32 _r = highlow32_0(_yhi);                              \
        if (_z >= _r)                                                        \
          { _ylo = bit(16)-1; _r = _z - _r + (uint32)_yhi; }                 \
          else                                                               \
          { divu_3216_1616(_z,_yhi, _ylo=,_r=); }                            \
        # x = 2^32*yhi^2 + 2*2^16*yhi*ylo + 2^17*r + (xlo mod 2^17),         \
        # 0 <= r < yhi + 2^15                                                \
        _xlo = (_r << 17) | (_xlo & (bit(17)-1));                            \
        # x = 2^32*yhi^2 + 2*2^16*yhi*ylo + 2^32*floor(r/2^15) + xlo         \
        _z = mulu16(_ylo,_ylo); # z = ylo^2                                  \
        # Versuche vom Rest 2^32*floor(r/2^15) + xlo  z zu subtrahieren.     \
        # Falls Rest >= z (d.h. r>=2^15 oder xlo>=z), ist ylo fertig,        \
        # und es gilt x=y^2 genau dann, wenn r<2^15 und xlo=z.               \
        # Sonst (d.h. r<2^15 und xlo<z), muß man ylo erniedrigen. Dazu       \
        # setzt man  ylo := ylo-1, z := z-(2*ylo+1),                         \
        # Rest := Rest + 2^17*yhi = xlo + 2^17*yhi >= 2^32 > z, also x>y^2.  \
        if (_r < bit(15))                                                    \
          { if (_xlo < _z)                                                   \
              { _ylo -= 1; sqrtp_zuweisung FALSE; }                          \
              else                                                           \
              { sqrtp_zuweisung (_xlo == _z); }                              \
          }                                                                  \
          else                                                               \
          { sqrtp_zuweisung FALSE; }                                         \
        y_zuweisung highlow32(_yhi,_ylo);                                    \
      }}
  #endif

# Eine 32-Bit-Zahl aus zwei aufeinanderfolgenden 16-Bit-Digits einer UDS
# zusammensetzen: highlow32_at(ptr)
  #if BIG_ENDIAN_P && defined(MC680X0)
    # ptr als 32-Bit-Pointer auffassen und darauf zugreifen
    #define highlow32_at(ptr)  (*(uint32*)(ptr))
  #else
    #define highlow32_at(ptr)  highlow32(((uint16*)(ptr))[0],((uint16*)(ptr))[1])
  #endif

# Eine 32-Bit-Zahl in zwei aufeinanderfolgende 16-Bit-Digits einer UDS abspeichern:
# set_highlow32_at(ptr,value32); wobei ptr und value32 Variablen.
  #if BIG_ENDIAN_P && defined(MC680X0)
    # ptr als 32-Bit-Pointer auffassen und darauf zugreifen
    #define set_highlow32_at(ptr,value32)  (*(uint32*)(ptr)=(value32))
  #else
    #define set_highlow32_at(ptr,value32)  (((uint16*)(ptr))[0]=high16(value32),((uint16*)(ptr))[1]=low16(value32))
  #endif

