// gcd(). // General includes. #include "cl_sysdep.h" // Specification. #include "cln/integer.h" // Implementation. #include "cl_I.h" #include "cl_DS.h" #include "cl_D.h" #include "cl_xmacros.h" namespace cln { #define GCD_ALGO 3 // 1: binär, 2: Schulmethode, 3: Lehmer #if (GCD_ALGO == 1) // binäre Methode: // (gcd a b) :== // b=0 --> (abs a) // a=0 --> (abs b) // sonst: // (abs a) und (abs b) in zwei Buffer packen, als Unsigned Digit Sequences. // [Schreibe oBdA wieder a,b] // (prog ((j 0)) // 1 {a,b >0} // (if (evenp a) // (if (evenp b) // (progn (incf j) (setq a (/ a 2)) (setq b (/ b 2)) (go 1)) // (go 4) // ) // (while (evenp b) (setq b (/ b 2))) // ) // 2 {a,b >0, beide ungerade} // (cond ((> a b)) // ((= a b) (go 5)) // ((< a b) (rotatef a b)) // ) // 3 {a,b >0, beide ungerade, a>b} // (setq a (- a b)) // 4 {a,b >0, a gerade, b ungerade} // (repeat (setq a (/ a 2)) (until (oddp a))) // (go 2) // 5 {a=b>0} // (return (ash a j)) // ) // weil es oft auftritt (insbesondere bei GCD's mehrerer Zahlen): // a=1 oder b=1 --> 1 const cl_I gcd (const cl_I& a, const cl_I& b) { if (eq(a,1)) { return 1; } // a=1 -> 1 if (eq(b,1)) { return 1; } // b=1 -> 1 if (eq(b,0)) { return abs(a); } // b=0 -> (abs a) if (eq(a,0)) { return abs(b); } // a=0 -> (abs b) CL_ALLOCA_STACK; var uintD* a_MSDptr; var uintC a_len; var uintD* a_LSDptr; var uintD* b_MSDptr; var uintC b_len; var uintD* b_LSDptr; // Macro: erzeugt die NUDS zu (abs x), erniedrigt num_stack #define I_abs_to_NUDS(x) \ I_to_NDS_1(x, x##_MSDptr = , x##_len = , x##_LSDptr = ); /* (nichtleere) NDS holen */\ if ((sintD)mspref(x##_MSDptr,0) < 0) /* falls <0, negieren: */\ { neg_loop_lsp(x##_LSDptr,x##_len); } \ if (mspref(x##_MSDptr,0) == 0) /* normalisieren (max. 1 Nulldigit entfernen) */\ { msshrink(x##_MSDptr); x##_len--; } I_abs_to_NUDS(a); // (abs a) als NUDS erzeugen I_abs_to_NUDS(b); // (abs b) als NUDS erzeugen // Jetzt ist a = a_MSDptr/a_len/a_LSDptr, b = b_MSDptr/b_len/b_LSDptr, // beides NUDS, und a_len>0, b_len>0. // Macro: Halbiere x. #define halb(x) \ { shift1right_loop_msp(x##_MSDptr,x##_len,0); /* um 1 Bit rechts schieben */ \ if (mspref(x##_MSDptr,0) == 0) { msshrink(x##_MSDptr); x##_len--; } /* normalisieren */\ } // Macro: Ob x gerade ist. #define evenp(x) \ ((lspref(x##_LSDptr,0) & bit(0)) ==0) { var uintL j = 0; label_1: // a,b >0 if (evenp(a)) { if (evenp(b)) { j++; halb(a); halb(b); goto label_1; } else goto label_4; } while (evenp(b)) { halb(b); } label_2: // a,b >0, beide ungerade // Vergleiche a und b: if (a_len > b_len) goto label_3; // a>b ? if (a_len == b_len) { var cl_signean vergleich = compare_loop_msp(a_MSDptr,b_MSDptr,a_len); if (vergleich > 0) goto label_3; // a>b ? if (vergleich == 0) goto label_5; // a=b ? } // a a,b vertauschen: swap(uintD*, a_MSDptr,b_MSDptr); swap(uintC, a_len,b_len); swap(uintD*, a_LSDptr,b_LSDptr); label_3: // a,b >0, beide ungerade, a>b // subtrahiere a := a - b if (!( subfrom_loop_lsp(b_LSDptr,a_LSDptr,b_len) ==0)) { dec_loop_lsp(a_LSDptr lspop b_len,a_len-b_len); } while (mspref(a_MSDptr,0) == 0) { msshrink(a_MSDptr); a_len--; } // normalisieren label_4: // a,b >0, a gerade, b ungerade do { halb(a); } while (evenp(a)); goto label_2; label_5: // a=b>0 // a zu einer NDS machen: return ash(NUDS_to_I(a_MSDptr,a_len),j); // ggT der ungeraden Anteile als Integer, mal 2^j } #undef evenp #undef halb #undef I_abs_to_NUDS } #endif /* GCD_ALGO == 1 */ #if (GCD_ALGO == 2) // Schulmethode: // (gcd a b) :== // [a:=(abs a), b:=(abs b), while b>0 do (a,b) := (b,(mod a b)), -> a] // verbessert: // a=0 -> (abs b) // b=0 -> (abs a) // a=1 -> 1 // b=1 -> 1 // a:=(abs a), b:=(abs b) // Falls a=b: return a; falls ab>0} // Falls b=1, return 1. {spart eine Division durch 1} // Sonst dividieren (divide a b), a:=b, b:=Rest. // Falls b=0, return a, sonst goto (*). const cl_I gcd (const cl_I& a, const cl_I& b) { if (eq(a,1)) { return 1; } // a=1 -> 1 if (eq(b,1)) { return 1; } // b=1 -> 1 if (eq(b,0)) { return abs(a); } // b=0 -> (abs a) if (eq(a,0)) { return abs(b); } // a=0 -> (abs b) // Beträge nehmen: {var cl_I abs_a = abs(a); var cl_I abs_b = abs(b); var cl_I& a = abs_a; var cl_I& b = abs_b; if (fixnump(a) && fixnump(b)) // ggT zweier Fixnums >0 { // bleibt Fixnum, da (gcd a b) <= (min a b) return L_to_FN(gcd(FN_to_UL(a),FN_to_UL(b))); } { var cl_signean vergleich = compare(a,b); if (vergleich == 0) { return a; } // a=b -> fertig if (vergleich < 0) { var cl_I tmp = a; a = b; b = a; } // a a,b vertauschen } loop // Hier a > b > 0 { if (eq(b,1)) { return 1; } // b=1 -> Ergebnis 1 { var cl_I_div_t div = cl_divide(a,b); a = b; b = div.remainder; } if (eq(b,0)) { return a; } } }} #endif /* GCD_ALGO == 2 */ #if (GCD_ALGO == 3) // Lehmer-Methode: // vgl. [ D. E. Knuth: The Art of Computer Programming, Vol. 2: Seminumerical // Algorithms, Sect. 4.5.2., Algorithm L ] // und [ Collins, Loos: SAC-2, Algorithms IGCD, DPCC ]. // (gcd a b) :== // a=0 -> (abs b) // b=0 -> (abs a) // a=1 -> 1 // b=1 -> 1 // a:=(abs a), b:=(abs b) // (*) {Hier a,b>0} // Falls a=b: return a; falls ab>0} // Falls (- (integer-length a) (integer-length b)) >= intDsize/2, // lohnt sich eine Division: (a,b) := (b , a mod b). Falls b=0: return a. // Falls dagegen 0 <= (- (integer-length a) (integer-length b)) < intDsize/2, // seien a' die führenden intDsize Bits von a // (2^(intDsize-1) <= a' < 2^intDsize) und b' die entsprechenden Bits von b // (2^(intDsize/2) <= b' <= a' < 2^intDsize). // Rechne den Euklid-Algorithmus mit Beifaktoren für ALLE Zahlen (a,b) aus, // die mit a' bzw. b' anfangen; das liefert x1,y1,x2,y2, so daß // ggT(a,b) = ggT(x1*a-y1*b,-x2*a+y2*b) und x1*a-y1*b>=0,-x2*a+y2*b>=0. // Genauer: Mit offensichtlicher Skalierung betrachten wir // a als beliebiges Element des Intervalls [a',a'+1) und // b als beliebiges Element des Intervalls [b',b'+1) und // führen den Euklid-Algorithmus schrittweise durch: // (x1,y1,z1) := (1,0,a'), (x2,y2,z2) := (0,1,b'), // Schleife: // {Hier x1*a'-y1*b'=z1, x1*a-y1*b in [z1-y1,z1+x1), z1-y1>=0, z1>0, // und -x2*a'+y2*b'=z2, -x2*a+y2*b in [z2-x2,z2+y2), z2-x2>=0, z2>0, // x1*y2-x2*y1=1, x1*z2+x2*z1=b', y1*z2+y2*z1=a'.} // Falls z1-y1>=z2+y2: // (x1,y1,z1) := (x1+x2,y1+y2,z1-z2), goto Schleife. // Falls z2-x2>=z1+x1: // (x2,y2,z2) := (x2+x1,y2+y1,z2-z1), goto Schleife. // Sonst muß man abbrechen. // {Zu den Schleifeninvarianten: // 1. Die Gleichungen x1*a'-y1*b'=z1, -x2*a'+y2*b'=z2, // x1*y2-x2*y1=1, x1*z2+x2*z1=b', y1*z2+y2*z1=a' mit Induktion. // 2. Die Ungleichungen x1>0, y1>=0, x2>=0, y2>0 mit Induktion. // 3. Die Ungleichungen z1>=0, z2>=0 nach Fallauswahl. // 4. Die Ungleichung x1+x2>0 aus x1*z2+x2*z1=b'>0, // die Ungleichung y1+y2>0 aus y1*z2+y2*z1=a'>0. // 5. Die Ungleichung z1>0 wegen Fallauswahl und y1+y2>0, // Die Ungleichung z2>0 wegen Fallauswahl und x1+x2>0. // 6. Die Ungleichungen z1-y1>=0, z2-x2>=0 wegen Fallauswahl. // 7. Die Ungleichung max(z1,z2) <= a' mit Induktion. // 8. Die Ungleichung x1+x2 <= x1*z2+x2*z1 = b', // die Ungleichung y1+y2 <= y1*z2+y2*z1 = a'. // Damit bleiben alle Größen im Intervall [0,beta), kein Überlauf. // 9. Die Ungleichungen z1+x1<=beta, z2+y2<=beta mit Induktion. // 10. x1*a-y1*b in (z1-y1,z1+x1) (bzw. [z1,z1+x1) bei y1=0), // -x2*a+y2*b in (z2-x2,z2+y2) (bzw. [z2,z2+y2) bei x2=0), // da a in a'+[0,1) und b in b'+[0,1). // Jedenfalls 0 < x1*a-y1*b < z1+x1 <= x2*z1+x1*z2 = b' falls x2>0, // und 0 < -x2*a+y2*b < z2+y2 <= y1*z2+y2*z1 = a' falls y1>0.} // Man kann natürlich auch mehrere Subtraktionsschritte auf einmal // durchführen: // Falls q := floor((z1-y1)/(z2+y2)) > 0 : // (x1,y1,z1) := (x1+q*x2,y1+q*y2,z1-q*z2), goto Schleife. // Falls q := floor((z2-x2)/(z1+x1)) > 0 : // (x2,y2,z2) := (x2+q*x1,y2+q*y1,z2-q*z1), goto Schleife. // {Am Schluß gilt -(x1+x2) < z1-z2 < y1+y2 und daher // z2-x2 <= b'/(x1+x2) < z1+x1, z1-y1 <= a'/(y1+y2) < z2+y2, // und - unter Berücksichtigung von x1*y2-x2*y1=1 - // z1-y1 <= b'/(x1+x2) < z2+y2, z2-x2 <= a'/(y1+y2) < z1+x1, // also max(z1-y1,z2-x2) <= min(b'/(x1+x2),a'/(y1+y2)) // <= max(b'/(x1+x2),a'/(y1+y2)) < min(z1+x1,z2+y2).} // Im Fall y1=x2=0 => x1=y2=1 (der nur bei a'=z1=z2=b' eintreten kann) // ersetze (a,b) := (a-b,b). {Beide >0, da a>b>0 war.} // Der Fall y1=0,x2>0 => x1=y2=1 => a' = z1 < z2+x2*z1 = b' // kann nicht eintreten. // Im Fall x2=0,y1>0 => x1=y2=1 ersetze (a,b) := (a-y1*b,b). // {Das ist OK, da 0 <= z1-y1 = a'-y1*(b'+1) < a-y1*b < a.} // Sonst (y1>0,x2>0) ersetze (a,b) := (x1*a-y1*b,-x2*a+y2*b). // {Das ist OK, da 0 <= z1-y1 = x1*a'-y1*(b'+1) < x1*a-y1*b // und 0 <= z2-x2 = -x2*(a'+1)+y2*b' < -x2*a+y2*b // und x1*a-y1*b < x1*(a'+1)-y1*b' = z1+x1 <= x2*z1+x1*z2 = b' <= b // und -x2*a+y2*b < -x2*a'+y2*(b'+1) = z2+y2 <= y1*z2+y2*z1 = a' <= a.} // goto (*). // Define this to 1 in order to use double-word sized a' and b'. // This gives better x1,y1,x2,y2, because normally the values x1,y1,x2,y2 // have only about intDsize/2 bits and so half of the multiplication work // is lost. Actually, this flag multiplies the gcd speed by 1.5, not 2.0. #define DOUBLE_SPEED 1 // Speed increases only for large integers. For small ones, computing // with double-word sized a' and b' is too costly. The threshold is // between 12 and 20, around 15. #define cl_gcd_double_threshold 16 // gcd of two single-word numbers >0 static uintD gcdD (uintD a, uintD b) { var uintD bit_j = (a | b); // endet mit einer 1 und j Nullen bit_j = bit_j ^ (bit_j - 1); // Maske = bit(j) | bit(j-1) | ... | bit(0) if (!((a & bit_j) ==0)) { if (!((b & bit_j) ==0)) goto odd_odd; else goto odd_even; } if (!((b & bit_j) ==0)) goto even_odd; NOTREACHED; loop { odd_odd: // a,b >0, beide ungerade // Vergleiche a und b: if (a == b) break; // a=b>0 -> fertig if (a > b) // a>b ? { a = a-b; even_odd: // a,b >0, a gerade, b ungerade do { a = a>>1; } while ((a & bit_j) ==0); } else // a0, a ungerade, b gerade do { b = b>>1; } while ((b & bit_j) ==0); } } // a=b>0 return a; } const cl_I gcd (const cl_I& a, const cl_I& b) { if (eq(a,1)) { return 1; } // a=1 -> 1 if (eq(b,1)) { return 1; } // b=1 -> 1 if (eq(b,0)) { return abs(a); } // b=0 -> (abs a) if (eq(a,0)) { return abs(b); } // a=0 -> (abs b) if (fixnump(a) && fixnump(b)) // ggT zweier Fixnums /=0 { var sintL a_ = FN_to_L(a); if (a_ < 0) { a_ = -a_; } var sintL b_ = FN_to_L(b); if (b_ < 0) { b_ = -b_; } return UL_to_I(gcd((uint32)a_,(uint32)b_)); } CL_ALLOCA_STACK; var uintD* a_MSDptr; var uintC a_len; var uintD* a_LSDptr; var uintD* b_MSDptr; var uintC b_len; var uintD* b_LSDptr; // Macro: erzeugt die NUDS zu (abs x), erniedrigt num_stack #define I_abs_to_NUDS(x) \ I_to_NDS_1(x, x##_MSDptr = , x##_len = , x##_LSDptr = ); /* (nichtleere) NDS holen */\ if ((sintD)mspref(x##_MSDptr,0) < 0) /* falls <0, negieren: */\ { neg_loop_lsp(x##_LSDptr,x##_len); } \ if (mspref(x##_MSDptr,0) == 0) /* normalisieren (max. 1 Nulldigit entfernen) */\ { msshrink(x##_MSDptr); x##_len--; } I_abs_to_NUDS(a); // (abs a) als NUDS erzeugen I_abs_to_NUDS(b); // (abs b) als NUDS erzeugen // Jetzt ist a = a_MSDptr/a_len/a_LSDptr, b = b_MSDptr/b_len/b_LSDptr, // beides NUDS, und a_len>0, b_len>0. // Platz für zwei Rechenregister besorgen, mit je max(a_len,b_len)+1 Digits: {var uintD* divroomptr; // Platz für Divisionsergebnis var uintD* c_LSDptr; var uintD* d_LSDptr; {var uintL c_len = (uintL)(a_len>=b_len ? a_len : b_len) + 1; num_stack_alloc(c_len,divroomptr=,c_LSDptr=); num_stack_alloc(c_len,,d_LSDptr=); // Jetzt ist ../c_len/c_LSDptr, ../c_len/d_LSDptr frei. } loop { // Hier a,b>0, beides NUDS. // Vergleiche a und b: if (a_len > b_len) goto a_greater_b; // a>b ? if (a_len == b_len) { var cl_signean vergleich = compare_loop_msp(a_MSDptr,b_MSDptr,a_len); if (vergleich > 0) goto a_greater_b; // a>b ? if (vergleich == 0) break; // a=b ? } // a a,b vertauschen: swap(uintD*, a_MSDptr,b_MSDptr); swap(uintC, a_len,b_len); swap(uintD*, a_LSDptr,b_LSDptr); a_greater_b: // Hier a>b>0, beides NUDS. if (b_len==1) // Beschleunigung eines häufigen Falles { var uintD b0 = mspref(b_MSDptr,0); if (b0==1) // a>b=1 -> Ergebnis 1. { return 1; } // a>b>1 -> evtl. Division durch b var uintD a0; if (a_len==1) { a0 = mspref(a_MSDptr,0); } else { a0 = divu_loop_msp(b0,a_MSDptr,a_len); if (a0==0) { return UD_to_I(b0); } } return UD_to_I(gcdD(a0,b0)); } // Entscheidung, ob Division oder Linearkombination: { var uintD a_msd; // führende intDsize Bits von a var uintD b_msd; // entsprechende Bits von b #if DOUBLE_SPEED var uintD a_nsd; // nächste intDsize Bits von a var uintD b_nsd; // entsprechende Bits von b #endif { var uintC len_diff = a_len-b_len; // Längendifferenz if (len_diff > 1) goto divide; // >=2 -> Bitlängendifferenz>intDsize -> dividieren #define bitlendiff_limit (intDsize/2) // sollte >0,0,<=intDsize) berechnen b_msd = mspref(b_MSDptr,0); #if HAVE_DD {var uintDD b_msdd = // 2 führende Digits von b (len_diff==0 ? highlowDD(b_msd, mspref(b_MSDptr,1)) : (uintDD)b_msd ); // a_msd_size+intDsize - b_msdd_size >= bitlendiff_limit -> dividieren: b_msd = lowD(b_msdd >> a_msd_size); if (b_msd < (uintD)bit(intDsize-bitlendiff_limit)) goto divide; #if DOUBLE_SPEED b_nsd = lowD(highlowDD(lowD(b_msdd), (b_len<=2-len_diff ? 0 : mspref(b_MSDptr,2-len_diff))) >> a_msd_size); #endif } {var uintDD a_msdd = // 2 führende Digits von a highlowDD(a_msd, mspref(a_MSDptr,1)); a_msd = lowD(a_msdd >> a_msd_size); #if DOUBLE_SPEED a_nsd = lowD(highlowDD(lowD(a_msdd), (a_len<=2 ? 0 : mspref(a_MSDptr,2))) >> a_msd_size); #endif } if (a_msd == b_msd) goto subtract; #else if (len_diff==0) { // a_msd_size - b_msd_size >= bitlendiff_limit -> dividieren: if ((a_msd_size > bitlendiff_limit) && (b_msd < (uintD)bit(a_msd_size-bitlendiff_limit)) ) goto divide; // Entscheidung für Linearkombination ist gefallen. // a_msd und b_msd so erweitern, daß a_msd die führenden // intDsize Bits von a enthält: {var uintC shiftcount = intDsize-a_msd_size; // Shiftcount nach links (>=0, 0) { a_msd = a_msd << shiftcount; b_msd = b_msd << shiftcount; a_msd |= mspref(a_MSDptr,1) >> a_msd_size; b_msd |= mspref(b_MSDptr,1) >> a_msd_size; } if (a_msd == b_msd) goto subtract; #if DOUBLE_SPEED a_nsd = mspref(a_MSDptr,1); b_nsd = mspref(b_MSDptr,1); if (shiftcount>0) { a_nsd = a_nsd << shiftcount; b_nsd = b_nsd << shiftcount; if (a_len>2) { a_nsd |= mspref(a_MSDptr,2) >> a_msd_size; b_nsd |= mspref(b_MSDptr,2) >> a_msd_size; } } #endif }} else // len_diff=1 { // a_msd_size+intDsize - b_msd_size >= bitlendiff_limit -> dividieren: if ((a_msd_size >= bitlendiff_limit) || (b_msd < (uintD)bit(a_msd_size+intDsize-bitlendiff_limit)) ) goto divide; // Entscheidung für Linearkombination ist gefallen. // a_msd und b_msd so erweitern, daß a_msd die führenden // intDsize Bits von a enthält: // 0 < a_msd_size < b_msd_size + bitlendiff_limit - intDsize <= bitlendiff_limit < intDsize. a_msd = (a_msd << (intDsize-a_msd_size)) | (mspref(a_MSDptr,1) >> a_msd_size); #if DOUBLE_SPEED a_nsd = mspref(a_MSDptr,1) << (intDsize-a_msd_size); b_nsd = b_msd << (intDsize-a_msd_size); a_nsd |= mspref(a_MSDptr,2) >> a_msd_size; b_nsd |= mspref(b_MSDptr,1) >> a_msd_size; #endif b_msd = b_msd >> a_msd_size; } #endif #undef bitlendiff_limit }} // Nun ist a_msd = a' > b' = b_msd. { // Euklid-Algorithmus auf den führenden Digits durchführen: var partial_gcd_result likobi; #if DOUBLE_SPEED if (a_len >= cl_gcd_double_threshold) { #if HAVE_DD partial_gcd(highlowDD(a_msd,a_nsd),highlowDD(b_msd,b_nsd),&likobi); // liefert x1,y1,x2,y2 #else partial_gcd(a_msd,a_nsd,b_msd,b_nsd,&likobi); // liefert x1,y1,x2,y2 #endif } else #endif { partial_gcd(a_msd,b_msd,&likobi); } // liefert x1,y1,x2,y2, aber nur halb so gut // Hier y1>0. if (likobi.x2==0) { // Ersetze (a,b) := (a-y1*b,b). if (likobi.y1==1) goto subtract; // einfacherer Fall // Dazu evtl. a um 1 Digit erweitern, so daß a_len=b_len+1: if (a_len == b_len) { lsprefnext(a_MSDptr) = 0; a_len++; } // und y1*b von a subtrahieren: mspref(a_MSDptr,0) -= mulusub_loop_lsp(likobi.y1,b_LSDptr,a_LSDptr,b_len); } else { // Ersetze (a,b) := (x1*a-y1*b,-x2*a+y2*b). // Dazu evtl. b um 1 Digit erweitern, so daß a_len=b_len: if (!(a_len==b_len)) { lsprefnext(b_MSDptr) = 0; b_len++; } // c := x1*a-y1*b bilden: mulu_loop_lsp(likobi.x1,a_LSDptr,c_LSDptr,a_len); /* lspref(c_LSDptr,a_len) -= */ mulusub_loop_lsp(likobi.y1,b_LSDptr,c_LSDptr,a_len); // d := -x2*a+y2*b bilden: mulu_loop_lsp(likobi.y2,b_LSDptr,d_LSDptr,a_len); /* lspref(d_LSDptr,a_len) -= */ mulusub_loop_lsp(likobi.x2,a_LSDptr,d_LSDptr,a_len); // Wir wissen, daß 0 < c < b und 0 < d < a. Daher müßten // lspref(c_LSDptr,a_len) und lspref(d_LSDptr,a_len) =0 sein. // a := c und b := d kopieren: copy_loop_lsp(c_LSDptr,a_LSDptr,a_len); copy_loop_lsp(d_LSDptr,b_LSDptr,a_len); // b normalisieren: while (mspref(b_MSDptr,0)==0) { msshrink(b_MSDptr); b_len--; } } } if (cl_false) { subtract: // Ersetze (a,b) := (a-b,b). if (!( subfrom_loop_lsp(b_LSDptr,a_LSDptr,b_len) ==0)) // Übertrag nach b_len Stellen, muß also a_len=b_len+1 sein. { mspref(a_MSDptr,0) -= 1; } } // a normalisieren: while (mspref(a_MSDptr,0)==0) { msshrink(a_MSDptr); a_len--; } } if (cl_false) { divide: // Ersetze (a,b) := (b , a mod b). {var uintD* old_a_LSDptr = a_LSDptr; var DS q; var DS r; cl_UDS_divide(a_MSDptr,a_len,a_LSDptr,b_MSDptr,b_len,b_LSDptr, divroomptr, &q,&r); a_MSDptr = b_MSDptr; a_len = b_len; a_LSDptr = b_LSDptr; // a := b b_len = r.len; if (b_len==0) break; // b=0 -> fertig b_LSDptr = old_a_LSDptr; // b übernimmt den vorherigen Platz von a b_MSDptr = copy_loop_lsp(r.LSDptr,b_LSDptr,b_len); // b := r kopieren goto a_greater_b; // Nun ist a>b>0 }} } } return NUDS_to_I(a_MSDptr,a_len); // NUDS a als Ergebnis #undef I_abs_to_NUDS } #endif /* GCD_ALGO == 3 */ } // namespace cln