12 #include "cl_integer.h"
15 // Dasselbe wie partial_gcd(z1,z2,erg), nur daß z1 und z2 Doppelworte sind.
16 // Bevor im Ergebnis erg ein Überlauf eintritt, wird abgebrochen.
20 static inline uintDD muluDD_unchecked(uintD q, uintDD a)
22 return muluD(q,lowD(a)) + highlowDD_0(muluD_unchecked(q,highD(a)));
25 // Division: liefert min(floor(x / y), 2^intDsize-1).
26 // Vorausgesetzt wird, daß x >= 2 * y > 0.
27 static uintD floorDD (uintDD x, uintDD y)
29 // vgl. Algorithmus für divu_3232_3232().
31 if (y < ((uintDD)1 << intDsize)) {
33 q = ~(uintD)0; // instead of overflow
35 divuD(x, (uintD)y, q =, );
40 integerlengthD(highD(y), shift=);
41 // NB: 0 < shift < intDsize since 2^intDsize <= y < 2^(2*intDsize-1).
42 // Determine q := floor((x>>shift) / ((y>>shift)+1)).
43 var uintD y_shifted = y >> shift;
46 q = highD(x) >> shift;
48 divuD(x,y_shifted, q =, );
50 // May need to increment q at most twice.
52 var uintDD p = muluDD_unchecked(q,y);
74 void partial_gcd (uintDD z1, uintDD z2, partial_gcd_result* erg)
81 // Hier ist z1-y1>=z2+y2.
82 // Bestimme q := floor((z1-y1)/(z2+y2)) >= 1 :
84 var uintDD zaehler = z1 - (uintDD)y1;
85 var uintDD nenner = z2 + (uintDD)y2;
86 // z2+y2 <= z1-y1 < beta^2 !
87 if (x2 > (~x1) >> 3) // x1 + 8*x2 >= beta ?
89 if (y2 > (~y1) >> 3) // y1 + 8*y2 >= beta ?
91 // Ist floor(zaehler,8) >= nenner ? Wenn nein -> do_subtract_1.
92 if ((zaehler >> 3) < nenner)
95 var uintD q = floorDD(zaehler,nenner);
97 var uintDD qx = muluD(q,x2);
98 if (qx > (uintDD)(~x1)) {
99 // Choose a smaller value for q, to avoid overflow of x1.
103 var uintDD qy = muluD(q,y2);
104 if (qy > (uintDD)(~y1)) {
105 // Choose a smaller value for q, to avoid overflow of y1.
111 z1 -= muluDD_unchecked(q,z2);
115 // Checks to avoid overflow.
116 if (x2 > ~x1) goto done;
117 if (y2 > ~y1) goto done;
119 if (z1 < z2) cl_abort();
121 // Now really subtract.
125 } while (z1 - (uintDD)y1 >= nenner);
128 if (z2 - (uintDD)x2 <= z1 + (uintDD)(x1-1)) goto done;
129 // Hier ist z2-x2>=z1+x1.
130 // Bestimme q := floor((z2-x2)/(z1+x1)) >= 1 :
132 var uintDD zaehler = z2 - (uintDD)x2;
133 var uintDD nenner = z1 + (uintDD)x1;
134 // z1+x1 <= z2-x2 < beta^2 !
135 if (x1 > (~x2) >> 3) // x2 + 8*x1 >= beta ?
137 if (y1 > (~y2) >> 3) // y2 + 8*y1 >= beta ?
139 // Ist floor(zaehler,8) >= nenner ? Wenn nein -> do_subtract_2.
140 if ((zaehler >> 3) < nenner)
143 var uintD q = floorDD(zaehler,nenner);
145 var uintDD qx = muluD(q,x1);
146 if (qx > (uintDD)(~x2)) {
147 // Choose a smaller value for q, to avoid overflow of x2.
151 var uintDD qy = muluD(q,y1);
152 if (qy > (uintDD)(~y2)) {
153 // Choose a smaller value for q, to avoid overflow of y2.
159 z2 -= muluDD_unchecked(q,z1);
163 // Checks to avoid overflow.
164 if (x1 > ~x2) goto done;
165 if (y1 > ~y2) goto done;
167 if (z2 < z1) cl_abort();
169 // Now really subtract.
173 } while (z2 - (uintDD)x2 >= nenner);
176 if (z1 - (uintDD)y1 <= z2 + (uintDD)(y2-1)) goto done;
179 // Keine Subtraktion (ohne Überlauf) mehr möglich.
180 erg->x1 = x1; erg->y1 = y1; erg->x2 = x2; erg->y2 = y2; // Ergebnis
185 // Division: liefert min(floor(xhi|xlo / yhi|ylo), 2^intDsize-1).
186 // Vorausgesetzt wird, daß xhi|xlo >= 2 * yhi|ylo > 0.
187 static uintD floorDD (uintD xhi, uintD xlo, uintD yhi, uintD ylo)
189 // vgl. Algorithmus für divu_3232_3232().
193 q = ~(uintD)0; // instead of overflow
195 divuD(xhi,xlo, ylo, q =, );
200 integerlengthD(yhi, shift=);
201 // NB: 0 < shift < intDsize since 2^intDsize <= y < 2^(2*intDsize-1).
202 // Determine q := floor((x>>shift) / ((y>>shift)+1)).
203 var uintD y_shifted = (uintD)(yhi << (intDsize-shift)) | (ylo >> shift);
208 divuD(xhi >> shift, (uintD)(xhi << (intDsize-shift)) | (xlo >> shift),
212 // May need to increment q at most twice.
216 muluD(q,ylo, phi =, plo =);
217 muluD(q,yhi, , phi +=);
219 if ((xhi < phi) || ((xhi == phi) && (xlo < plo)))
227 if ((xhi > yhi) || ((xhi == yhi) && (xlo >= ylo))) {
233 if ((xhi > yhi) || ((xhi == yhi) && (xlo >= ylo))) {
240 if ((xhi > yhi) || ((xhi == yhi) && (xlo >= ylo)))
248 void partial_gcd (uintD z1hi, uintD z1lo, uintD z2hi, uintD z2lo, partial_gcd_result* erg)
255 // Hier ist z1-y1>=z2+y2.
256 // Bestimme q := floor((z1-y1)/(z2+y2)) >= 1 :
258 var uintD zaehlerhi = z1hi;
259 var uintD zaehlerlo = z1lo - y1;
260 if (zaehlerlo > z1lo) { zaehlerhi--; }
261 var uintD nennerhi = z2hi;
262 var uintD nennerlo = z2lo + y2;
263 if (nennerlo < z2lo) { nennerhi++; }
264 // z2+y2 <= z1-y1 < beta^2 !
265 if (x2 > (~x1) >> 3) // x1 + 8*x2 >= beta ?
267 if (y2 > (~y1) >> 3) // y1 + 8*y2 >= beta ?
269 // Ist floor(zaehler,8) >= nenner ? Wenn nein -> do_subtract_1.
270 if ((zaehlerhi >> 3) < nennerhi)
272 if ((zaehlerhi >> 3) == nennerhi)
273 if (((uintD)(zaehlerhi << (intDsize-3)) | (zaehlerlo >> 3)) < nennerlo)
276 var uintD q = floorDD(zaehlerhi,zaehlerlo,nennerhi,nennerlo);
282 muluD(q,x2, qxhi =, qx =);
283 if ((qxhi > 0) || (qx > ~x1)) {
284 // Choose a smaller value for q, to avoid overflow of x1.
291 muluD(q,y2, qyhi =, qy =);
292 if ((qyhi > 0) || (qy > ~y1)) {
293 // Choose a smaller value for q, to avoid overflow of y1.
303 muluD(q,z2lo, qzhi =, qzlo =);
304 muluD(q,z2hi, , qzhi +=);
313 // Checks to avoid overflow.
314 if (x2 > ~x1) goto done;
315 if (y2 > ~y1) goto done;
317 if (z1hi < z2hi) cl_abort();
318 if (z1hi == z2hi) if (z1lo < z2lo) cl_abort();
320 // Now really subtract.
327 var uintD z1dec_hi = z1hi;
328 var uintD z1dec_lo = z1lo - y1;
331 if (z1dec_hi < nennerhi)
333 if (z1dec_hi == nennerhi)
334 if (z1dec_lo < nennerlo)
340 var uintD z1inc_hi = z1hi;
341 var uintD z1inc_lo = z1lo + x1-1;
344 var uintD z2dec_hi = z2hi;
345 var uintD z2dec_lo = z2lo - x2;
348 if (z2dec_hi < z1inc_hi) goto done;
349 if (z2dec_hi == z1inc_hi) if (z2dec_lo <= z1inc_lo) goto done;
351 // Hier ist z2-x2>=z1+x1.
352 // Bestimme q := floor((z2-x2)/(z1+x1)) >= 1 :
354 var uintD zaehlerhi = z2hi;
355 var uintD zaehlerlo = z2lo - x2;
356 if (zaehlerlo > z2lo) { zaehlerhi--; }
357 var uintD nennerhi = z1hi;
358 var uintD nennerlo = z1lo + x1;
359 if (nennerlo < z1lo) { nennerhi++; }
360 // z1+x1 <= z2-x2 < beta^2 !
361 if (x1 > (~x2) >> 3) // x2 + 8*x1 >= beta ?
363 if (y1 > (~y2) >> 3) // y2 + 8*y1 >= beta ?
365 // Ist floor(zaehler,8) >= nenner ? Wenn nein -> do_subtract_2.
366 if ((zaehlerhi >> 3) < nennerhi)
368 if ((zaehlerhi >> 3) == nennerhi)
369 if (((uintD)(zaehlerhi << (intDsize-3)) | (zaehlerlo >> 3)) < nennerlo)
372 var uintD q = floorDD(zaehlerhi,zaehlerlo,nennerhi,nennerlo);
378 muluD(q,x1, qxhi =, qx =);
379 if ((qxhi > 0) || (qx > ~x2)) {
380 // Choose a smaller value for q, to avoid overflow of x2.
387 muluD(q,y1, qyhi =, qy =);
388 if ((qyhi > 0) || (qy > ~y2)) {
389 // Choose a smaller value for q, to avoid overflow of y2.
399 muluD(q,z1lo, qzhi =, qzlo =);
400 muluD(q,z1hi, , qzhi +=);
409 // Checks to avoid overflow.
410 if (x1 > ~x2) goto done;
411 if (y1 > ~y2) goto done;
413 if (z2hi < z1hi) cl_abort();
414 if (z2hi == z1hi) if (z2lo < z1lo) cl_abort();
416 // Now really subtract.
423 var uintD z2dec_hi = z2hi;
424 var uintD z2dec_lo = z2lo - x2;
427 if (z2dec_hi < nennerhi)
429 if (z2dec_hi == nennerhi)
430 if (z2dec_lo < nennerlo)
436 var uintD z2inc_hi = z2hi;
437 var uintD z2inc_lo = z2lo + y2-1;
440 var uintD z1dec_hi = z1hi;
441 var uintD z1dec_lo = z1lo - y1;
444 if (z1dec_hi < z2inc_hi) goto done;
445 if (z1dec_hi == z2inc_hi) if (z1dec_lo <= z2inc_lo) goto done;
449 // Keine Subtraktion (ohne Überlauf) mehr möglich.
450 erg->x1 = x1; erg->y1 = y1; erg->x2 = x2; erg->y2 = y2; // Ergebnis