]> www.ginac.de Git - cln.git/blob - src/base/digitseq/cl_DS.h
* src/base/digitseq/cl_DS.h: <gmp.h> is not included extern "C"
[cln.git] / src / base / digitseq / cl_DS.h
1 // Digit sequence arithmetic
2
3 #ifndef _CL_DS_H
4 #define _CL_DS_H
5
6 #include "cln/types.h"
7 #include "cl_gmpconfig.h"
8 #include "cl_D.h"
9 #include "cl_DS_endian.h"
10 #include "cl_alloca.h"
11
12 namespace cln {
13
14 // Digit Sequence (DS)
15 // a memory range with n digits (n an uintC),
16 // between two pointers MSDptr and LSDptr.
17 #if CL_DS_BIG_ENDIAN_P
18 //  MSDptr                  LSDptr = MSDptr+n
19 // | MSD ............. LSD |
20 // [short: MSDptr/n/LSDptr ]
21 // In C: uintD* MSDptr, uintC len, MSDptr[0] ... MSDptr[len-1] are the digits.
22 #else
23 //  LSDptr                  MSDptr = LSDptr+n
24 // | LSD ............. MSD |
25 // In C: uintD* LSDptr, uintC len, LSDptr[0] ... LSDptr[len-1] are the digits.
26 #endif
27 // If n = 0, this represents the number 0.
28 // If n > 0, the most significant bit (i.e. bit (intDsize-1) of
29 //           MSDptr[CL_DS_BIG_ENDIAN_P?0:-1]) is the sign bit. If the sign
30 //           bit were repeated infinitely often, one would get an
31 //           "infinite bit sequence".
32 //
33 // A Normalised Digit Sequence (NDS) is one for which the MSD is necessary,
34 // i.e. n = 0 or (n > 0 and the most significant intDsize+1 bits are not
35 // all the same).
36
37 // Unsigned Digit Sequence (UDS)
38 // like DS, but without sign.
39 //
40 // Normalized Unsigned Digit Sequence (NUDS):
41 // an UDS for which the MSD is necessary, i.e. n = 0 or
42 // (n > 0 and the most significant intDsize bits are not all zero).
43
44 // For the construction of constant DS, using "digit_header":
45 #define D1(byte0)  (uintD)(byte0)
46 #define D2(byte0,byte1)  (((uintD)(byte0)<<8)|(uintD)(byte1))
47 #define D4(byte0,byte1,byte2,byte3)  (((uintD)(byte0)<<24)|((uintD)(byte1)<<16)|((uintD)(byte2)<<8)|((uintD)(byte3)))
48 #define D8(byte0,byte1,byte2,byte3,byte4,byte5,byte6,byte7)  (((uintD)(byte0)<<56)|((uintD)(byte1)<<48)|((uintD)(byte2)<<40)|((uintD)(byte3)<<32)|((uintD)(byte4)<<24)|((uintD)(byte5)<<16)|((uintD)(byte6)<<8)|((uintD)(byte7)))
49
50 struct DS {
51         uintD* MSDptr;
52         unsigned int len;
53         uintD* LSDptr;
54 };
55
56 // Endianness independent access of digit sequences:
57 // mspref(MSDptr,i)    access a most significant digit
58 // lspref(LSDptr,i)    access a least significant digit
59 // msshrink(MSDptr)    shrinks the DS by throwing away the MSD
60 // msprefnext(MSDptr)  combines mspref(MSDptr,0) and msshrink(MSDptr)
61 // lsshrink(LSDptr)    shrinks the DS by throwing away the LSD
62 // lsprefnext(LSDptr)  combines lspref(LSDptr,0) and lsshrink(LSDptr)
63 // mspop     pointer operator corresponding to msshrink, arg is widened to an uintP
64 // lspop     pointer operator corresponding to lsshrink, arg is widened to an uintP
65 #if CL_DS_BIG_ENDIAN_P
66   #define mspref(p,i)  (p)[i]
67   #define lspref(p,i)  (p)[-(uintP)(i)-1]
68   #define msshrink(p)  (p)++
69   #define msprefnext(p)  (*(p)++)
70   #define lsshrink(p)  (p)--
71   #define lsprefnext(p)  (*--(p))
72   #define mspop  +
73   #define lspop  -
74 #else
75   #define mspref(p,i)  (p)[-(uintP)(i)-1]
76   #define lspref(p,i)  (p)[i]
77   #define msshrink(p)  (p)--
78   #define msprefnext(p)  (*--(p))
79   #define lsshrink(p)  (p)++
80   #define lsprefnext(p)  (*(p)++)
81   #define mspop  -
82   #define lspop  +
83 #endif
84
85 // Endianness independent macros for turning an array into a digit sequence.
86 // arrayMSDptr(array,length)  returns the MSDptr of array[0..length-1]
87 // arrayLSDptr(array,length)  returns the LSDptr of array[0..length-1]
88 #if CL_DS_BIG_ENDIAN_P
89   #define arrayMSDptr(array,length)  &(array)[0]
90   #define arrayLSDptr(array,length)  &(array)[length]
91 #else
92   #define arrayMSDptr(array,length)  &(array)[length]
93   #define arrayLSDptr(array,length)  &(array)[0]
94 #endif
95 #define arrayLSref(array,length,i)  lspref(arrayLSDptr(array,length),i)
96
97
98 // These functions on digit sequences are either inline C++ functions
99 // or external assembler functions (see files cl_asm_*).
100
101
102 // See which functions are defined as external functions.
103 #include "cl_asm.h"
104
105
106 // Declare the external functions.
107
108 extern "C" {
109
110 #ifdef COPY_LOOPS
111
112 extern uintD* copy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count);
113
114 extern uintD* copy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count);
115
116 #endif
117
118 #ifdef FILL_LOOPS
119
120 extern uintD* fill_loop_up (uintD* destptr, uintC count, uintD filler);
121
122 extern uintD* fill_loop_down (uintD* destptr, uintC count, uintD filler);
123
124 #endif
125
126 #ifdef CLEAR_LOOPS
127
128 extern uintD* clear_loop_up (uintD* destptr, uintC count);
129
130 extern uintD* clear_loop_down (uintD* destptr, uintC count);
131
132 #endif
133
134 #ifdef TEST_LOOPS
135
136 extern cl_boolean test_loop_up (const uintD* ptr, uintC count);
137
138 extern cl_boolean test_loop_down (const uintD* ptr, uintC count);
139
140 #endif
141
142 #if CL_DS_BIG_ENDIAN_P
143
144 #ifdef LOG_LOOPS
145
146 extern void or_loop_up (uintD* xptr, const uintD* yptr, uintC count);
147
148 extern void xor_loop_up (uintD* xptr, const uintD* yptr, uintC count);
149
150 extern void and_loop_up (uintD* xptr, const uintD* yptr, uintC count);
151
152 extern void eqv_loop_up (uintD* xptr, const uintD* yptr, uintC count);
153
154 extern void nand_loop_up (uintD* xptr, const uintD* yptr, uintC count);
155
156 extern void nor_loop_up (uintD* xptr, const uintD* yptr, uintC count);
157
158 extern void andc2_loop_up (uintD* xptr, const uintD* yptr, uintC count);
159
160 extern void orc2_loop_up (uintD* xptr, const uintD* yptr, uintC count);
161
162 extern void not_loop_up (uintD* xptr, uintC count);
163
164 #endif
165
166 #ifdef TEST_LOOPS
167
168 extern cl_boolean and_test_loop_up (const uintD* xptr, const uintD* yptr, uintC count);
169
170 extern cl_signean compare_loop_up (const uintD* xptr, const uintD* yptr, uintC count);
171
172 #endif
173
174 #ifdef ADDSUB_LOOPS
175
176 extern uintD add_loop_down (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count);
177
178 extern uintD addto_loop_down (const uintD* sourceptr, uintD* destptr, uintC count);
179
180 extern uintD inc_loop_down (uintD* ptr, uintC count);
181
182 extern uintD sub_loop_down (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count);
183
184 extern uintD subx_loop_down (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count, uintD carry);
185
186 extern uintD subfrom_loop_down (const uintD* sourceptr, uintD* destptr, uintC count);
187
188 extern uintD dec_loop_down (uintD* ptr, uintC count);
189
190 extern uintD neg_loop_down (uintD* ptr, uintC count);
191
192 #endif
193
194 #ifdef SHIFT_LOOPS
195
196 extern uintD shift1left_loop_down (uintD* ptr, uintC count);
197
198 extern uintD shiftleft_loop_down (uintD* ptr, uintC count, uintC i, uintD carry);
199
200 extern uintD shiftleftcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i);
201
202 extern uintD shift1right_loop_up (uintD* ptr, uintC count, uintD carry);
203
204 extern uintD shiftright_loop_up (uintD* ptr, uintC count, uintC i);
205
206 extern uintD shiftrightsigned_loop_up (uintD* ptr, uintC count, uintC i);
207
208 extern uintD shiftrightcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry);
209
210 #endif
211
212 #ifdef MUL_LOOPS
213
214 extern uintD mulusmall_loop_down (uintD digit, uintD* ptr, uintC len, uintD newdigit);
215
216 extern void mulu_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
217
218 extern uintD muluadd_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
219
220 extern uintD mulusub_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
221
222 #endif
223
224 #ifdef DIV_LOOPS
225
226 extern uintD divu_loop_up (uintD digit, uintD* ptr, uintC len);
227
228 extern uintD divucopy_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
229
230 #endif
231
232 #else // !CL_DS_BIG_ENDIAN_P
233
234 #ifdef LOG_LOOPS
235
236 extern void or_loop_down (uintD* xptr, const uintD* yptr, uintC count);
237
238 extern void xor_loop_down (uintD* xptr, const uintD* yptr, uintC count);
239
240 extern void and_loop_down (uintD* xptr, const uintD* yptr, uintC count);
241
242 extern void eqv_loop_down (uintD* xptr, const uintD* yptr, uintC count);
243
244 extern void nand_loop_down (uintD* xptr, const uintD* yptr, uintC count);
245
246 extern void nor_loop_down (uintD* xptr, const uintD* yptr, uintC count);
247
248 extern void andc2_loop_down (uintD* xptr, const uintD* yptr, uintC count);
249
250 extern void orc2_loop_down (uintD* xptr, const uintD* yptr, uintC count);
251
252 extern void not_loop_down (uintD* xptr, uintC count);
253
254 #endif
255
256 #ifdef TEST_LOOPS
257
258 extern cl_boolean and_test_loop_down (const uintD* xptr, const uintD* yptr, uintC count);
259
260 extern cl_signean compare_loop_down (const uintD* xptr, const uintD* yptr, uintC count);
261
262 #endif
263
264 #ifdef ADDSUB_LOOPS
265
266 extern uintD add_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count);
267
268 extern uintD addto_loop_up (const uintD* sourceptr, uintD* destptr, uintC count);
269
270 extern uintD inc_loop_up (uintD* ptr, uintC count);
271
272 extern uintD sub_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count);
273
274 extern uintD subx_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count, uintD carry);
275
276 extern uintD subfrom_loop_up (const uintD* sourceptr, uintD* destptr, uintC count);
277
278 extern uintD dec_loop_up (uintD* ptr, uintC count);
279
280 extern uintD neg_loop_up (uintD* ptr, uintC count);
281
282 #endif
283
284 #ifdef SHIFT_LOOPS
285
286 extern uintD shift1left_loop_up (uintD* ptr, uintC count);
287
288 extern uintD shiftleft_loop_up (uintD* ptr, uintC count, uintC i, uintD carry);
289
290 extern uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i);
291
292 extern uintD shift1right_loop_down (uintD* ptr, uintC count, uintD carry);
293
294 extern uintD shiftright_loop_down (uintD* ptr, uintC count, uintC i);
295
296 extern uintD shiftrightsigned_loop_down (uintD* ptr, uintC count, uintC i);
297
298 extern uintD shiftrightcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry);
299
300 #endif
301
302 #ifdef MUL_LOOPS
303
304 extern uintD mulusmall_loop_up (uintD digit, uintD* ptr, uintC len, uintD newdigit);
305
306 extern void mulu_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
307
308 extern uintD muluadd_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
309
310 extern uintD mulusub_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
311
312 #endif
313
314 #ifdef DIV_LOOPS
315
316 extern uintD divu_loop_down (uintD digit, uintD* ptr, uintC len);
317
318 extern uintD divucopy_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len);
319
320 #endif
321
322 #endif // !CL_DS_BIG_ENDIAN_P
323
324 // Independently of CL_DS_BIG_ENDIAN_P:
325
326 #ifdef TEST_LOOPS
327
328 extern cl_signean compare_loop_up (const uintD* xptr, const uintD* yptr, uintC count);
329
330 #endif
331
332 #ifdef LOG_LOOPS
333
334 extern void xor_loop_up (uintD* xptr, const uintD* yptr, uintC count);
335
336 #endif
337
338 #ifdef SHIFT_LOOPS
339
340 extern uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i);
341
342 extern void shiftxor_loop_up (uintD* xptr, const uintD* yptr, uintC count, uintC i);
343
344 #endif
345
346 } // "C" extern.
347
348
349 #if defined(CL_USE_GMP)
350
351 // Supersede the functions by wrappers around calls to gmp mpn,
352 // for those functions where gmp is believed to be faster.
353
354 }  // namespace cln
355
356 #include <gmp.h>
357
358 namespace cln {
359
360 #if 0 // not worth it, since gmp's mpn_cmp is not optimized
361 inline cl_signean compare_loop_down (const uintD* xptr, const uintD* yptr, uintC count)
362 {
363         return mpn_cmp(xptr-count,yptr-count,count);
364 }
365 #endif
366
367 inline uintD add_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count)
368 {
369         if (count == 0)
370                 return 0;
371         return mpn_add_n(destptr,sourceptr1,sourceptr2,count);
372 }
373
374 inline uintD addto_loop_up (const uintD* sourceptr, uintD* destptr, uintC count)
375 {
376         if (count == 0)
377                 return 0;
378         return mpn_add_n(destptr,destptr,sourceptr,count);
379 }
380
381 inline uintD inc_loop_up (uintD* ptr, uintC count)
382 {
383         if (count == 0)
384                 return 1;
385         return mpn_add_1(ptr,ptr,count,1);
386 }
387
388 inline uintD sub_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count)
389 {
390         if (count == 0)
391                 return 0;
392         return mpn_sub_n(destptr,sourceptr1,sourceptr2,count);
393 }
394
395 inline uintD subx_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count, uintD carry)
396 {
397         if (count == 0)
398                 return carry;
399         var uintD res_carry = mpn_sub_n(destptr,sourceptr1,sourceptr2,count);
400         if (carry)
401                 res_carry |= mpn_sub_1(destptr,destptr,count,1);
402         return res_carry;
403 }
404
405 inline uintD subfrom_loop_up (const uintD* sourceptr, uintD* destptr, uintC count)
406 {
407         if (count == 0)
408                 return 0;
409         return mpn_sub_n(destptr,destptr,sourceptr,count);
410 }
411
412 inline uintD dec_loop_up (uintD* ptr, uintC count)
413 {
414         if (count == 0)
415                 return (uintD)(-1);
416         return -mpn_sub_1(ptr,ptr,count,1);
417 }
418
419 #if !defined(ADDSUB_LOOPS)
420 // No equivalent for this in gmp. But we need this function, so write it in C.
421 inline uintD neg_loop_up (uintD* ptr, uintC count)
422 {
423         // erstes Digit /=0 suchen:
424         until (count==0) { if (!(*ptr == 0)) goto L1; ptr++; count--; }
425         return 0;
426     L1: // erstes Digit /=0 gefunden, ab jetzt gibt's Carrys
427         *ptr = - *ptr; count--; // 1 Digit negieren
428         dotimesC(count,count, { ptr++; *ptr = ~ *ptr; } ); // alle anderen Digits invertieren
429         return (uintD)(-1);
430 }
431 #endif
432
433 #define ADDSUB_LOOPS
434
435 inline uintD shift1left_loop_up (uintD* ptr, uintC count)
436 {
437         if (count == 0)
438                 return 0;
439         return mpn_lshift(ptr,ptr,count,1);
440 }
441
442 inline uintD shiftleft_loop_up (uintD* ptr, uintC count, uintC i, uintD carry)
443 {
444         if (count == 0)
445                 return carry;
446         var uintD res_carry = mpn_lshift(ptr,ptr,count,i);
447         ptr[0] |= carry;
448         return res_carry;
449 }
450
451 inline uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
452 {
453         if (count == 0)
454                 return 0;
455         return mpn_lshift(destptr,sourceptr,count,i);
456 }
457
458 inline uintD shift1right_loop_down (uintD* ptr, uintC count, uintD carry)
459 {
460         if (count == 0)
461                 return carry;
462         var uintD res_carry = mpn_rshift(ptr-count,ptr-count,count,1);
463         if (carry)
464                 ptr[-1] |= bit(intDsize-1);
465         return res_carry;
466 }
467
468 inline uintD shiftright_loop_down (uintD* ptr, uintC count, uintC i)
469 {
470         if (count == 0)
471                 return 0;
472         return mpn_rshift(ptr-count,ptr-count,count,i);
473 }
474
475 inline uintD shiftrightsigned_loop_down (uintD* ptr, uintC count, uintC i)
476 {
477         var uintD carry = ((sintD)ptr[-1] >> (intDsize-1)) << (intDsize-i);
478         var uintD res_carry = mpn_rshift(ptr-count,ptr-count,count,i);
479         ptr[-1] |= carry;
480         return res_carry;
481 }
482
483 inline uintD shiftrightcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry)
484 {
485         carry = carry << (intDsize-i);
486         if (count == 0)
487                 return carry;
488         var uintD res_carry = mpn_rshift(destptr-count,sourceptr-count,count,i);
489         destptr[-1] |= carry;
490         return res_carry;
491 }
492
493 #define SHIFT_LOOPS
494
495 inline uintD mulusmall_loop_up (uintD digit, uintD* ptr, uintC len, uintD newdigit)
496 {
497         if (len == 0)
498                 return newdigit;
499         var uintD res_carry = mpn_mul_1(ptr,ptr,len,digit);
500         res_carry += mpn_add_1(ptr,ptr,len,newdigit);
501         return res_carry;
502 }
503
504 inline void mulu_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
505 {
506         destptr[len] = (len==0 ? 0 : mpn_mul_1(destptr,sourceptr,len,digit));
507 }
508
509 inline uintD muluadd_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
510 {
511         if (len == 0)
512                 return 0;
513         return mpn_addmul_1(destptr,sourceptr,len,digit);
514 }
515
516 inline uintD mulusub_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
517 {
518         if (len == 0)
519                 return 0;
520         return mpn_submul_1(destptr,sourceptr,len,digit);
521 }
522
523 #define MUL_LOOPS
524
525 inline uintD divu_loop_up (uintD digit, uintD* ptr, uintC len)
526 {
527         return mpn_divrem_1(ptr,0,ptr,len,digit);
528 }
529
530 inline uintD divu_loop_down (uintD digit, uintD* ptr, uintC len)
531 {
532         return mpn_divrem_1(ptr-len,0,ptr-len,len,digit);
533 }
534
535 inline uintD divucopy_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
536 {
537         return mpn_divrem_1(destptr,0,sourceptr,len,digit);
538 }
539
540 inline uintD divucopy_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
541 {
542         return mpn_divrem_1(destptr-len,0,sourceptr-len,len,digit);
543 }
544
545 #define DIV_LOOPS
546
547 #endif // defined(CL_USE_GMP)
548
549
550 // Define the missing functions as inline functions.
551
552 #ifndef COPY_LOOPS
553
554 // Kopierschleife:
555 // destptr = copy_loop_up(sourceptr,destptr,count);
556 // kopiert count (uintC>=0) Digits aufwärts von sourceptr nach destptr
557 // und liefert das neue destptr.
558   inline uintD* copy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count)
559     { dotimesC(count,count, { *destptr++ = *sourceptr++; } );
560       return destptr;
561     }
562
563 // Kopierschleife:
564 // destptr = copy_loop_down(sourceptr,destptr,count);
565 // kopiert count (uintC>=0) Digits abwärts von sourceptr nach destptr
566 // und liefert das neue destptr.
567   inline uintD* copy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count)
568     { dotimesC(count,count, { *--destptr = *--sourceptr; } );
569       return destptr;
570     }
571
572 #endif
573
574 #ifndef FILL_LOOPS
575
576 // Füllschleife:
577 // destptr = fill_loop_up(destptr,count,filler);
578 // kopiert count (uintC>=0) mal das Digit filler aufwärts nach destptr
579 // und liefert das neue destptr.
580   inline uintD* fill_loop_up (uintD* destptr, uintC count, uintD filler)
581     { dotimesC(count,count, { *destptr++ = filler; } );
582       return destptr;
583     }
584
585 // Füllschleife:
586 // destptr = fill_loop_down(destptr,count,filler);
587 // kopiert count (uintC>=0) mal das Digit filler abwärts nach destptr
588 // und liefert das neue destptr.
589   inline uintD* fill_loop_down (uintD* destptr, uintC count, uintD filler)
590     { dotimesC(count,count, { *--destptr = filler; } );
591       return destptr;
592     }
593
594 #endif
595
596 #ifndef CLEAR_LOOPS
597
598 // Lösch-Schleife:
599 // destptr = clear_loop_up(destptr,count);
600 // löscht count (uintC>=0) Digits aufwärts ab destptr
601 // und liefert das neue destptr.
602   inline uintD* clear_loop_up (uintD* destptr, uintC count)
603     { dotimesC(count,count, { *destptr++ = 0; } );
604       return destptr;
605     }
606
607 // Lösch-Schleife:
608 // destptr = clear_loop_down(destptr,count);
609 // löscht count (uintC>=0) Digits abwärts ab destptr
610 // und liefert das neue destptr.
611   inline uintD* clear_loop_down (uintD* destptr, uintC count)
612     { dotimesC(count,count, { *--destptr = 0; } );
613       return destptr;
614     }
615
616 #endif
617
618 #ifndef TEST_LOOPS
619
620 // Test-Schleife:
621 // test_loop_up(ptr,count)
622 // testet count (uintC>=0) Digits aufwärts ab ptr, ob darunter eines /=0 ist.
623 // Ergebnis /=0, falls ja.
624   inline cl_boolean test_loop_up (const uintD* ptr, uintC count)
625     { dotimesC(count,count, { if (*ptr++) return cl_true; } );
626       return cl_false;
627     }
628
629 // Test-Schleife:
630 // test_loop_down(ptr,count)
631 // testet count (uintC>=0) Digits abwärts ab ptr, ob darunter eines /=0 ist.
632 // Ergebnis /=0, falls ja.
633   inline cl_boolean test_loop_down (const uintD* ptr, uintC count)
634     { dotimesC(count,count, { if (*--ptr) return cl_true; } );
635       return cl_false;
636     }
637
638 #endif
639
640 #if CL_DS_BIG_ENDIAN_P
641
642 #ifndef LOG_LOOPS
643
644 // OR-Schleife:
645 // or_loop_up(xptr,yptr,count);
646 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
647 // mit Ziel ab xptr durch OR.
648   inline void or_loop_up (uintD* xptr, const uintD* yptr, uintC count)
649     { dotimesC(count,count, { *xptr++ |= *yptr++; } ); }
650
651 // XOR-Schleife:
652 // xor_loop_up(xptr,yptr,count);
653 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
654 // mit Ziel ab xptr durch XOR.
655   inline void xor_loop_up (uintD* xptr, const uintD* yptr, uintC count)
656     { dotimesC(count,count, { *xptr++ ^= *yptr++; } ); }
657
658 // AND-Schleife:
659 // and_loop_up(xptr,yptr,count);
660 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
661 // mit Ziel ab xptr durch AND.
662   inline void and_loop_up (uintD* xptr, const uintD* yptr, uintC count)
663     { dotimesC(count,count, { *xptr++ &= *yptr++; } ); }
664
665 // EQV-Schleife:
666 // eqv_loop_up(xptr,yptr,count);
667 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
668 // mit Ziel ab xptr durch EQV (NOT XOR).
669   inline void eqv_loop_up (uintD* xptr, const uintD* yptr, uintC count)
670     { dotimesC(count,count,
671         {var uintD temp = ~ (*xptr ^ *yptr++); *xptr++ = temp; }
672         );
673     }
674
675 // NAND-Schleife:
676 // nand_loop_up(xptr,yptr,count);
677 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
678 // mit Ziel ab xptr durch NAND (NOT AND).
679   inline void nand_loop_up (uintD* xptr, const uintD* yptr, uintC count)
680     { dotimesC(count,count,
681         {var uintD temp = ~ (*xptr & *yptr++); *xptr++ = temp; }
682         );
683     }
684
685 // NOR-Schleife:
686 // nor_loop_up(xptr,yptr,count);
687 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
688 // mit Ziel ab xptr durch NOR (NOT OR).
689   inline void nor_loop_up (uintD* xptr, const uintD* yptr, uintC count)
690     { dotimesC(count,count,
691         {var uintD temp = ~ (*xptr | *yptr++); *xptr++ = temp; }
692         );
693     }
694
695 // ANDC2-Schleife:
696 // andc2_loop_up(xptr,yptr,count);
697 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
698 // mit Ziel ab xptr durch ANDC2 (AND NOT).
699   inline void andc2_loop_up (uintD* xptr, const uintD* yptr, uintC count)
700     { dotimesC(count,count, { *xptr++ &= ~(*yptr++); } ); }
701
702 // ORC2-Schleife:
703 // orc2_loop_up(xptr,yptr,count);
704 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
705 // mit Ziel ab xptr durch ORC2 (OR NOT).
706   inline void orc2_loop_up (uintD* xptr, const uintD* yptr, uintC count)
707     { dotimesC(count,count, { *xptr++ |= ~(*yptr++); } ); }
708
709 // NOT-Schleife:
710 // not_loop_up(xptr,count);
711 // verknüpft count (uintC>0) Digits aufwärts ab xptr mit Ziel ab xptr
712 // durch NOT.
713   inline void not_loop_up (uintD* xptr, uintC count)
714     { dotimespC(count,count,
715         {var uintD temp = ~ (*xptr); *xptr++ = temp; }
716         );
717     }
718
719 #endif
720
721 #ifndef TEST_LOOPS
722
723 // AND-Test-Schleife:
724 // and_test_loop_up(xptr,yptr,count);
725 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr durch AND
726 // und testet, ob sich dabei ein Digit /=0 ergibt. Ergebnis cl_true, falls ja.
727   inline cl_boolean and_test_loop_up (const uintD* xptr, const uintD* yptr, uintC count)
728     { dotimesC(count,count, { if (*xptr++ & *yptr++) return cl_true; } );
729       return cl_false;
730     }
731
732 // Vergleichsschleife:
733 // result = compare_loop_up(xptr,yptr,count);
734 // vergleicht nacheinander xptr[0] mit yptr[0], xptr[1] mit yptr[1], usw.,
735 // insgesamt count Digits, und liefert 0 falls alle gleich sind,
736 // +1 falls zuerst ein xptr[i]>yptr[i] ist,
737 // -1 falls zuerst ein xptr[i]<yptr[i] ist.
738   inline cl_signean compare_loop_up (const uintD* xptr, const uintD* yptr, uintC count)
739     { dotimesC(count,count,
740         { if (!(*xptr++ == *yptr++))
741             // verschiedene Digits gefunden
742             return (*--xptr > *--yptr ? signean_plus : signean_minus);
743         });
744       return signean_null; // alle Digits gleich
745     }
746
747 #endif
748
749 #ifndef ADDSUB_LOOPS
750
751 // Additionsschleife:
752 // übertrag = add_loop_down(sourceptr1,sourceptr2,destptr,count);
753 // addiert count (uintC>=0) Digits abwärts von sourceptr1, von sourceptr2
754 // abwärts nach destptr und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
755   inline uintD add_loop_down (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count)
756     { var uintD source1;
757       var uintD source2;
758       if (!(count==0))
759       do { source1 = *--sourceptr1;
760            source2 = *--sourceptr2;
761            *--destptr = source1 + source2;
762            if (source1 > (uintD)(~source2)) goto carry_1;
763            carry_0:
764            count--;
765          }
766          until (count==0);
767       return 0;
768       do { source1 = *--sourceptr1;
769            source2 = *--sourceptr2;
770            *--destptr = source1 + source2 + 1;
771            if (source1 < (uintD)(~source2)) goto carry_0;
772            carry_1:
773            count--;
774          }
775          until (count==0);
776       return 1;
777     }
778
779 // Additionsschleife:
780 // übertrag = addto_loop_down(sourceptr,destptr,count);
781 // addiert count (uintC>=0) Digits abwärts von sourceptr, von destptr
782 // abwärts nach destptr und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
783   inline uintD addto_loop_down (const uintD* sourceptr, uintD* destptr, uintC count)
784     { var uintD source1;
785       var uintD source2;
786       if (!(count==0))
787       do { source1 = *--sourceptr;
788            source2 = *--destptr;
789            *destptr = source1 + source2;
790            if (source1 > (uintD)(~source2)) goto carry_1;
791            carry_0:
792            count--;
793          }
794          until (count==0);
795       return 0;
796       do { source1 = *--sourceptr;
797            source2 = *--destptr;
798            *destptr = source1 + source2 + 1;
799            if (source1 < (uintD)(~source2)) goto carry_0;
800            carry_1:
801            count--;
802          }
803          until (count==0);
804       return 1;
805     }
806
807 // Incrementierschleife:
808 // übertrag = inc_loop_down(ptr,count);
809 // incrementiert count (uintC>=0) Digits abwärts von ptr, so lange bis kein
810 // Übertrag mehr auftritt und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
811   inline uintD inc_loop_down (uintD* ptr, uintC count)
812     { dotimesC(count,count,
813         { if (!( ++(*--ptr) == 0 )) return 0; } // kein weiterer Übertrag
814         );
815       return 1; // weiterer Übertrag
816     }
817
818 // Subtraktionsschleife:
819 // übertrag = sub_loop_down(sourceptr1,sourceptr2,destptr,count);
820 // subtrahiert count (uintC>=0) Digits abwärts von sourceptr1, von sourceptr2
821 // abwärts nach destptr und liefert den Übertrag (0 oder /=0, was -1 bedeutet).
822   inline uintD sub_loop_down (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count)
823     { var uintD source1;
824       var uintD source2;
825       if (!(count==0))
826       do { source1 = *--sourceptr1;
827            source2 = *--sourceptr2;
828            *--destptr = source1 - source2;
829            if (source1 < source2) goto carry_1;
830            carry_0:
831            count--;
832          }
833          until (count==0);
834       return 0;
835       do { source1 = *--sourceptr1;
836            source2 = *--sourceptr2;
837            *--destptr = source1 - source2 - 1;
838            if (source1 > source2) goto carry_0;
839            carry_1:
840            count--;
841          }
842          until (count==0);
843       return (uintD)(-1);
844     }
845
846 // Subtraktionsschleife:
847 // übertrag = subx_loop_down(sourceptr1,sourceptr2,destptr,count,carry);
848 // subtrahiert count (uintC>=0) Digits abwärts von sourceptr1 und addiert
849 // einen Carry (0 oder -1), von sourceptr2 abwärts nach destptr und
850 // liefert den Übertrag (0 oder /=0, was -1 bedeutet).
851   inline uintD subx_loop_down (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count, uintD carry)
852     { var uintD source1;
853       var uintD source2;
854       if (carry==0)
855         { if (!(count==0))
856             do { source1 = *--sourceptr1;
857                  source2 = *--sourceptr2;
858                  *--destptr = source1 - source2;
859                  if (source1 < source2) goto carry_1;
860                  carry_0:
861                  count--;
862                }
863                until (count==0);
864           return 0;
865         }
866         else
867         { if (!(count==0))
868             do { source1 = *--sourceptr1;
869                  source2 = *--sourceptr2;
870                  *--destptr = source1 - source2 - 1;
871                  if (source1 > source2) goto carry_0;
872                  carry_1:
873                  count--;
874                }
875                until (count==0);
876           return (uintD)(-1);
877     }   }
878
879 // Subtraktionsschleife:
880 // übertrag = subfrom_loop_down(sourceptr,destptr,count);
881 // subtrahiert count (uintC>=0) Digits abwärts von sourceptr, von destptr
882 // abwärts nach destptr (dest := dest - source)
883 // und liefert den Übertrag (0 oder /=0, was -1 bedeutet).
884   inline uintD subfrom_loop_down (const uintD* sourceptr, uintD* destptr, uintC count)
885     { var uintD source1;
886       var uintD source2;
887       if (!(count==0))
888       do { source1 = *--destptr;
889            source2 = *--sourceptr;
890            *destptr = source1 - source2;
891            if (source1 < source2) goto carry_1;
892            carry_0:
893            count--;
894          }
895          until (count==0);
896       return 0;
897       do { source1 = *--destptr;
898            source2 = *--sourceptr;
899            *destptr = source1 - source2 - 1;
900            if (source1 > source2) goto carry_0;
901            carry_1:
902            count--;
903          }
904          until (count==0);
905       return (uintD)(-1);
906     }
907
908 // Decrementierschleife:
909 // übertrag = dec_loop_down(ptr,count);
910 // decrementiert count (uintC>=0) Digits abwärts von ptr, so lange bis kein
911 // Übertrag mehr auftritt und liefert den Übertrag (0 oder -1).
912   inline uintD dec_loop_down (uintD* ptr, uintC count)
913     { dotimesC(count,count,
914         { if (!( (*--ptr)-- == 0 )) return 0; } // kein weiterer Übertrag
915         );
916       return (uintD)(-1); // weiterer Übertrag
917     }
918
919 // Negierschleife:
920 // übertrag = neg_loop_down(ptr,count);
921 // negiert count (uintC>=0) Digits abwärts von ptr,
922 // und liefert den Übertrag (0 oder -1).
923   inline uintD neg_loop_down (uintD* ptr, uintC count)
924     { // erstes Digit /=0 suchen:
925       until (count==0) { if (!(*--ptr == 0)) goto L1; count--; }
926       return 0;
927       L1: // erstes Digit /=0 gefunden, ab jetzt gibt's Carrys
928       *ptr = - *ptr; count--; // 1 Digit negieren
929       dotimesC(count,count, { --ptr; *ptr = ~ *ptr; } ); // alle anderen Digits invertieren
930       return (uintD)(-1);
931     }
932
933 #endif
934
935 #ifndef SHIFT_LOOPS
936
937 // Schiebeschleife um 1 Bit nach links:
938 // übertrag = shift1left_loop_down(ptr,count);
939 // schiebt count (uintC>=0) Digits abwärts von ptr um 1 Bit nach links,
940 // und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
941   #if HAVE_DD
942   inline uintD shift1left_loop_down (uintD* ptr, uintC count)
943     { var uintDD accu = 0;
944       dotimesC(count,count,
945         { accu = ((uintDD)(*--ptr)<<1)+accu; *ptr = lowD(accu);
946           accu = (uintDD)(highD(accu));
947         });
948       return (uintD)accu;
949     }
950   #else
951   inline uintD shift1left_loop_down (uintD* ptr, uintC count)
952     { var uintD carry = 0;
953       dotimesC(count,count,
954         { var uintD accu = *--ptr;
955           *ptr = (accu<<1) | carry;
956           carry = accu>>(intDsize-1);
957         });
958       return carry;
959     }
960   #endif
961
962 // Schiebeschleife um i Bits nach links:
963 // übertrag = shiftleft_loop_down(ptr,count,i,übertrag_init);
964 // schiebt count (uintC>=0) Digits abwärts von ptr um i Bits (0<i<intDsize)
965 // nach links, schiebt dabei die i Bits aus übertrag_init rechts rein,
966 // und liefert den Übertrag (was links rauskommt, >=0, <2^i).
967   #if HAVE_DD
968   inline uintD shiftleft_loop_down (uintD* ptr, uintC count, uintC i, uintD carry)
969     { var uintDD accu = (uintDD)carry;
970       dotimesC(count,count,
971         { accu = ((uintDD)(*--ptr)<<i)+accu; *ptr = lowD(accu);
972           accu = (uintDD)(highD(accu));
973         });
974       return (uintD)accu;
975     }
976   #else
977   inline uintD shiftleft_loop_down (uintD* ptr, uintC count, uintC i, uintD carry)
978     { var uintC j = intDsize-i;
979       dotimesC(count,count,
980         { var uintD accu = *--ptr;
981           *ptr = (accu<<i) | carry;
982           carry = accu>>j;
983         });
984       return carry;
985     }
986   #endif
987
988 // Schiebe- und Kopierschleife um i Bits nach links:
989 // übertrag = shiftleftcopy_loop_down(sourceptr,destptr,count,i);
990 // kopiert count (uintC>=0) Digits abwärts von sourceptr nach destptr
991 // und schiebt sie dabei um i Bits (0<i<intDsize) nach links,
992 // wobei ganz rechts mit i Nullbits aufgefüllt wird,
993 // und liefert den Übertrag (was links rauskommt, >=0, <2^i).
994   #if HAVE_DD
995   inline uintD shiftleftcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
996     { var uintDD accu = 0;
997       dotimesC(count,count,
998         { accu = ((uintDD)(*--sourceptr)<<i)+accu; *--destptr = lowD(accu);
999           accu = (uintDD)(highD(accu));
1000         });
1001       return (uintD)accu;
1002     }
1003   #else
1004   inline uintD shiftleftcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
1005     { var uintC j = intDsize-i;
1006       var uintD carry = 0;
1007       dotimesC(count,count,
1008         { var uintD accu = *--sourceptr;
1009           *--destptr = (accu<<i) | carry;
1010           carry = accu>>j;
1011         });
1012       return carry;
1013     }
1014   #endif
1015
1016 // Schiebeschleife um 1 Bit nach rechts:
1017 // übertrag = shift1right_loop_up(ptr,count,übertrag_init);
1018 // schiebt count (uintC>=0) Digits aufwärts von ptr um 1 Bit nach rechts,
1019 // wobei links das Bit übertrag_init (sollte =0 oder =-1 sein) hineingeschoben
1020 // wird, und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
1021   #if HAVE_DD
1022   inline uintD shift1right_loop_up (uintD* ptr, uintC count, uintD carry)
1023     { var uintDD accu = (sintDD)(sintD)carry & ((uintDD)1 << (2*intDsize-1)); // 0 oder bit(2*intDsize-1)
1024       dotimesC(count,count,
1025         { accu = (highlowDD_0(*ptr)>>1)+accu; *ptr++ = highD(accu);
1026           accu = highlowDD_0(lowD(accu));
1027         });
1028       return highD(accu);
1029     }
1030   #else
1031   inline uintD shift1right_loop_up (uintD* ptr, uintC count, uintD carry)
1032     { carry = carry << (intDsize-1); // carry zu einem einzigen Bit machen
1033       dotimesC(count,count,
1034         { var uintD accu = *ptr;
1035           *ptr++ = (accu >> 1) | carry;
1036           carry = accu << (intDsize-1);
1037         });
1038       return carry;
1039     }
1040   #endif
1041
1042 // Schiebeschleife um i Bits nach rechts:
1043 // übertrag = shiftright_loop_up(ptr,count,i);
1044 // schiebt count (uintC>=0) Digits aufwärts von ptr um i Bits (0<i<intDsize)
1045 // nach rechts, wobei links Nullen eingeschoben werden,
1046 // und liefert den Übertrag (was rechts rauskommt, als Bits intDsize-1..intDsize-i).
1047   #if HAVE_DD
1048   inline uintD shiftright_loop_up (uintD* ptr, uintC count, uintC i)
1049     { var uintDD accu = 0;
1050       dotimesC(count,count,
1051         { // Die oberen i Bits von (uintD)accu bilden hier den Übertrag.
1052           accu = highlowDD_0(lowD(accu));
1053           // Die oberen i Bits von (uintDD)accu bilden hier den Übertrag.
1054           accu = (highlowDD_0(*ptr)>>i)+accu; *ptr++ = highD(accu);
1055         });
1056       return lowD(accu);
1057     }
1058   #else
1059   inline uintD shiftright_loop_up (uintD* ptr, uintC count, uintC i)
1060     { var uintC j = intDsize-i;
1061       var uintD carry = 0;
1062       dotimesC(count,count,
1063         { var uintD accu = *ptr;
1064           *ptr++ = (accu >> i) | carry;
1065           carry = accu << j;
1066         });
1067       return carry;
1068     }
1069   #endif
1070
1071 // Schiebeschleife um i Bits nach rechts:
1072 // übertrag = shiftrightsigned_loop_up(ptr,count,i);
1073 // schiebt count (uintC>0) Digits aufwärts von ptr um i Bits (0<i<intDsize)
1074 // nach rechts, wobei links das MSBit ver-i-facht wird,
1075 // und liefert den Übertrag (was rechts rauskommt, als Bits intDsize-1..intDsize-i).
1076   #if HAVE_DD
1077   inline uintD shiftrightsigned_loop_up (uintD* ptr, uintC count, uintC i)
1078     { var uintDD accu = // Übertrag mit i Vorzeichenbits initialisieren
1079                            highlowDD_0(sign_of_sintD((sintD)(*ptr)))>>i;
1080       dotimespC(count,count,
1081         { // Die oberen i Bits von (uintD)accu bilden hier den Übertrag.
1082           accu = highlowDD_0(lowD(accu));
1083           // Die oberen i Bits von (uintDD)accu bilden hier den Übertrag.
1084           accu = (highlowDD_0(*ptr)>>i)+accu; *ptr++ = highD(accu);
1085         });
1086       return lowD(accu);
1087     }
1088   #else
1089   inline uintD shiftrightsigned_loop_up (uintD* ptr, uintC count, uintC i)
1090     { var uintC j = intDsize-i;
1091       var uintD carry;
1092       { var uintD accu = *ptr;
1093         *ptr++ = (sintD)accu >> i;
1094         carry = accu << j;
1095         count--;
1096       }
1097       dotimesC(count,count,
1098         { var uintD accu = *ptr;
1099           *ptr++ = (accu >> i) | carry;
1100           carry = accu << j;
1101         });
1102       return carry;
1103     }
1104   #endif
1105
1106 // Schiebe- und Kopier-Schleife um i Bits nach rechts:
1107 // übertrag = shiftrightcopy_loop_up(sourceptr,destptr,count,i,carry);
1108 // kopiert count (uintC>=0) Digits aufwärts von sourceptr nach destptr
1109 // und schiebt sie dabei um i Bits (0<i<intDsize) nach rechts, wobei carry
1110 // (sozusagen als sourceptr[-1]) die i Bits ganz links bestimmt,
1111 // und liefert den Übertrag (was rechts rauskommt, als Bits intDsize-1..intDsize-i).
1112   #if HAVE_DD
1113   inline uintD shiftrightcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry)
1114     { var uintDD accu = // Übertrag mit carry initialisieren
1115                            highlowDD_0(carry)>>i;
1116       dotimesC(count,count,
1117         { // Die oberen i Bits von (uintD)accu bilden hier den Übertrag.
1118           accu = highlowDD_0(lowD(accu));
1119           // Die oberen i Bits von (uintDD)accu bilden hier den Übertrag.
1120           accu = (highlowDD_0(*sourceptr++)>>i)+accu; *destptr++ = highD(accu);
1121         });
1122       return lowD(accu);
1123     }
1124   #else
1125   inline uintD shiftrightcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry)
1126     { var uintC j = intDsize-i;
1127       carry = carry << j;
1128       dotimesC(count,count,
1129         { var uintD accu = *sourceptr++;
1130           *destptr++ = (accu >> i) | carry;
1131           carry = accu << j;
1132         });
1133       return carry;
1134     }
1135   #endif
1136
1137 #endif
1138
1139 #ifndef MUL_LOOPS
1140
1141 // Multiplikations-Einfachschleife:
1142 // Multipliziert eine UDS mit einem kleinen Digit und addiert ein kleines Digit.
1143 // mulusmall_loop_down(digit,ptr,len,newdigit)
1144 // multipliziert die UDS  ptr[-len..-1]  mit digit (>=2, <=36),
1145 // addiert dabei newdigit (>=0, <digit) zur letzten Ziffer,
1146 // und liefert den Carry (>=0, <digit).
1147   #if HAVE_DD
1148   inline uintD mulusmall_loop_down (uintD digit, uintD* ptr, uintC len, uintD newdigit)
1149     { var uintDD carry = newdigit;
1150       dotimesC(len,len,
1151         { // Hier ist 0 <= carry < digit.
1152           carry = carry + muluD(digit,*--ptr);
1153           // Hier ist 0 <= carry < 2^intDsize*digit.
1154           *ptr = lowD(carry);
1155           carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) < digit
1156         });
1157       return lowD(carry);
1158     }
1159   #else
1160   inline uintD mulusmall_loop_down (uintD digit, uintD* ptr, uintC len, uintD newdigit)
1161     { var uintD carry = newdigit;
1162       dotimesC(len,len,
1163         { // Hier ist 0 <= carry < digit.
1164           var uintD hi;
1165           var uintD lo;
1166           muluD(digit,*--ptr,hi=,lo=);
1167           // Hier ist 0 <= 2^intDsize*hi + lo + carry < 2^intDsize*digit.
1168           lo += carry; if (lo < carry) { hi += 1; }
1169           *ptr = lo;
1170           carry = hi;
1171         });
1172       return carry;
1173     }
1174   #endif
1175
1176 // Multiplikations-Einfachschleife:
1177 // Multipliziert eine UDS mit einem Digit und legt das Ergebnis in einer
1178 // zweiten UDS ab.
1179 // mulu_loop_down(digit,sourceptr,destptr,len);
1180 // multipliziert die UDS  sourceptr[-len..-1]  (len>0)
1181 // mit dem einzelnen  digit
1182 // und legt das Ergebnis in der UDS  destptr[-len-1..-1]  ab.
1183   #if HAVE_DD
1184   inline void mulu_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1185     { var uintDD carry = 0;
1186       dotimespC(len,len,
1187         { // Hier ist carry=digit=0 oder 0 <= carry < digit.
1188           carry = carry + muluD(digit,*--sourceptr);
1189           // Hier ist carry=digit=0 oder 0 <= carry < 2^intDsize*digit.
1190           *--destptr = lowD(carry);
1191           carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) < digit
1192         });
1193       *--destptr = lowD(carry);
1194     }
1195   #else
1196   inline void mulu_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1197     { var uintD carry = 0;
1198       dotimespC(len,len,
1199         { // Hier ist carry=digit=0 oder 0 <= carry < digit.
1200           var uintD hi;
1201           var uintD lo;
1202           muluD(digit,*--sourceptr,hi=,lo=);
1203           // Hier ist 0 <= 2^intDsize*hi + lo + carry < 2^intDsize*digit oder hi=lo=carry=digit=0.
1204           lo += carry; if (lo < carry) { hi += 1; }
1205           *--destptr = lo;
1206           carry = hi;
1207         });
1208       *--destptr = carry;
1209     }
1210   #endif
1211
1212 // Multiplikations-Einfachschleife mit Akkumulation:
1213 // Multipliziert eine UDS mit einem Digit und addiert das Ergebnis zu einer
1214 // zweiten UDS auf.
1215 // muluadd_loop_down(digit,sourceptr,destptr,len);
1216 // multipliziert die UDS  sourceptr[-len..-1]  (len>0)
1217 // mit dem einzelnen digit, legt das Ergebnis in der UDS  destptr[-len..-1]
1218 // ab und liefert den weiteren Übertrag.
1219   #if HAVE_DD
1220   inline uintD muluadd_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1221     { var uintDD carry = 0;
1222       if (!(digit==0))
1223         { dotimespC(len,len,
1224             { // Hier ist 0 <= carry <= digit.
1225               carry = carry + muluD(digit,*--sourceptr) + (uintDD)*--destptr;
1226               // Hier ist 0 <= carry <= 2^intDsize*digit + 2^intDsize-1.
1227               *destptr = lowD(carry);
1228               carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) <= digit
1229             });
1230         }
1231       return lowD(carry);
1232     }
1233   #else
1234   inline uintD muluadd_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1235     { var uintD carry = 0;
1236       if (!(digit==0))
1237         { dotimespC(len,len,
1238             { // Hier ist 0 <= carry <= digit.
1239               var uintD hi;
1240               var uintD lo;
1241               muluD(digit,*--sourceptr,hi=,lo=);
1242               // Hier ist 0 <= 2^intDsize*hi + lo + carry + *--destptr <= 2^intDsize*digit+2^intDsize-1.
1243               lo += carry; if (lo < carry) { hi += 1; }
1244               carry = *--destptr;
1245               lo += carry; if (lo < carry) { hi += 1; }
1246               *destptr = lo;
1247               carry = hi;
1248             });
1249         }
1250       return carry;
1251     }
1252   #endif
1253
1254 // Multiplikations-Einfachschleife mit Diminution:
1255 // Multipliziert eine UDS mit einem Digit und subtrahiert das Ergebnis von
1256 // einer zweiten UDS.
1257 // mulusub_loop_down(digit,sourceptr,destptr,len);
1258 // multipliziert die UDS  sourceptr[-len..-1]  (len>0)  mit dem einzelnen
1259 // digit, subtrahiert das Ergebnis von der UDS  destptr[-len..-1]  und liefert
1260 // den weiteren Übertrag (>=0, evtl. von destptr[-len-1] zu subtrahieren).
1261   #if HAVE_DD
1262   inline uintD mulusub_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1263     { var uintDD carry = 0;
1264       if (!(digit==0))
1265         { dotimespC(len,len,
1266             { // Hier ist 0 <= carry <= digit.
1267               carry = carry + muluD(digit,*--sourceptr) + (uintD)(~(*--destptr));
1268               // Hier ist 0 <= carry <= 2^intDsize*digit + 2^intDsize-1.
1269               *destptr = ~lowD(carry);
1270               carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) <= digit
1271               // Hier ist 0 <= carry <= digit.
1272             });
1273           return lowD(carry);
1274         }
1275         else
1276         return 0; // nichts zu subtrahieren -> kein Übertrag
1277     }
1278   #else
1279   inline uintD mulusub_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1280     { var uintD carry = 0;
1281       if (!(digit==0))
1282         { dotimespC(len,len,
1283             { // Hier ist 0 <= carry <= digit.
1284               var uintD hi;
1285               var uintD lo;
1286               muluD(digit,*--sourceptr,hi=,lo=);
1287               // Hier ist 0 <= 2^intDsize*hi + lo + carry + ~(*--destptr) <= 2^intDsize*digit+2^intDsize-1.
1288               lo += carry; if (lo < carry) { hi += 1; }
1289               carry = *--destptr;
1290               *destptr = carry - lo; if (carry < lo) { hi += 1; }
1291               carry = hi;
1292             });
1293           return carry;
1294         }
1295         else
1296         return 0; // nichts zu subtrahieren -> kein Übertrag
1297     }
1298   #endif
1299
1300 #endif
1301
1302 #ifndef DIV_LOOPS
1303
1304 // Divisions-Einfachschleife:
1305 // Dividiert eine UDS durch ein Digit.
1306 // divu_loop_up(digit,ptr,len)
1307 // dividiert die UDS  ptr[0..len-1] durch digit,
1308 // legt das Ergebnis in derselben UDS ab, und liefert den Rest (>=0, <digit).
1309   #if HAVE_DD
1310   inline uintD divu_loop_up (uintD digit, uintD* ptr, uintC len)
1311     { var uintD rest = 0;
1312       dotimesC(len,len,
1313         { divuD(highlowDD(rest,*ptr),digit,*ptr =, rest =); ptr++; }
1314         );
1315       return rest;
1316     }
1317   #else
1318   inline uintD divu_loop_up (uintD digit, uintD* ptr, uintC len)
1319     { var uintD rest = 0;
1320       dotimesC(len,len,
1321         { divuD(rest,*ptr,digit,*ptr =, rest =); ptr++; }
1322         );
1323       return rest;
1324     }
1325   #endif
1326
1327 // Divisions-Einfachschleife:
1328 // Dividiert eine UDS durch ein Digit und legt das Ergebnis in einer
1329 // zweiten UDS ab.
1330 // divucopy_loop_up(digit,sourceptr,destptr,len)
1331 // dividiert die UDS  sourceptr[0..len-1]  durch digit,
1332 // legt das Ergebnis in der UDS  destptr[0..len-1]  ab,
1333 // und liefert den Rest (>=0, <digit).
1334   #if HAVE_DD
1335   inline uintD divucopy_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1336     { var uintD rest = 0;
1337       dotimesC(len,len,
1338         { divuD(highlowDD(rest,*sourceptr++),digit,*destptr++ =, rest =); }
1339         );
1340       return rest;
1341     }
1342   #else
1343   inline uintD divucopy_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1344     { var uintD rest = 0;
1345       dotimesC(len,len,
1346         { divuD(rest,*sourceptr++,digit,*destptr++ =, rest =); }
1347         );
1348       return rest;
1349     }
1350   #endif
1351
1352 #endif
1353
1354 #else // !CL_DS_BIG_ENDIAN_P
1355
1356 #ifndef LOG_LOOPS
1357
1358 // OR-Schleife:
1359 // or_loop_down(xptr,yptr,count);
1360 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1361 // mit Ziel ab xptr durch OR.
1362   inline void or_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1363     { dotimesC(count,count, { *--xptr |= *--yptr; } ); }
1364
1365 // XOR-Schleife:
1366 // xor_loop_down(xptr,yptr,count);
1367 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1368 // mit Ziel ab xptr durch XOR.
1369   inline void xor_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1370     { dotimesC(count,count, { *--xptr ^= *--yptr; } ); }
1371
1372 // AND-Schleife:
1373 // and_loop_down(xptr,yptr,count);
1374 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1375 // mit Ziel ab xptr durch AND.
1376   inline void and_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1377     { dotimesC(count,count, { *--xptr &= *--yptr; } ); }
1378
1379 // EQV-Schleife:
1380 // eqv_loop_down(xptr,yptr,count);
1381 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1382 // mit Ziel ab xptr durch EQV (NOT XOR).
1383   inline void eqv_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1384     { dotimesC(count,count,
1385         {var uintD temp = ~ (*--xptr ^ *--yptr); *xptr = temp; }
1386         );
1387     }
1388
1389 // NAND-Schleife:
1390 // nand_loop_down(xptr,yptr,count);
1391 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1392 // mit Ziel ab xptr durch NAND (NOT AND).
1393   inline void nand_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1394     { dotimesC(count,count,
1395         {var uintD temp = ~ (*--xptr & *--yptr); *xptr = temp; }
1396         );
1397     }
1398
1399 // NOR-Schleife:
1400 // nor_loop_down(xptr,yptr,count);
1401 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1402 // mit Ziel ab xptr durch NOR (NOT OR).
1403   inline void nor_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1404     { dotimesC(count,count,
1405         {var uintD temp = ~ (*--xptr | *--yptr); *xptr = temp; }
1406         );
1407     }
1408
1409 // ANDC2-Schleife:
1410 // andc2_loop_down(xptr,yptr,count);
1411 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1412 // mit Ziel ab xptr durch ANDC2 (AND NOT).
1413   inline void andc2_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1414     { dotimesC(count,count, { *--xptr &= ~(*--yptr); } ); }
1415
1416 // ORC2-Schleife:
1417 // orc2_loop_down(xptr,yptr,count);
1418 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr
1419 // mit Ziel ab xptr durch ORC2 (OR NOT).
1420   inline void orc2_loop_down (uintD* xptr, const uintD* yptr, uintC count)
1421     { dotimesC(count,count, { *--xptr |= ~(*--yptr); } ); }
1422
1423 // NOT-Schleife:
1424 // not_loop_down(xptr,count);
1425 // verknüpft count (uintC>0) Digits abwärts ab xptr mit Ziel ab xptr
1426 // durch NOT.
1427   inline void not_loop_down (uintD* xptr, uintC count)
1428     { dotimespC(count,count,
1429         {var uintD temp = ~ (*--xptr); *xptr = temp; }
1430         );
1431     }
1432
1433 #endif
1434
1435 #ifndef TEST_LOOPS
1436
1437 // AND-Test-Schleife:
1438 // and_test_loop_down(xptr,yptr,count);
1439 // verknüpft count (uintC>=0) Digits abwärts ab xptr und ab yptr durch AND
1440 // und testet, ob sich dabei ein Digit /=0 ergibt. Ergebnis cl_true, falls ja.
1441   inline cl_boolean and_test_loop_down (const uintD* xptr, const uintD* yptr, uintC count)
1442     { dotimesC(count,count, { if (*--xptr & *--yptr) return cl_true; } );
1443       return cl_false;
1444     }
1445
1446 // Vergleichsschleife:
1447 // result = compare_loop_down(xptr,yptr,count);
1448 // vergleicht nacheinander xptr[-1] mit yptr[-1], xptr[-2] mit yptr[-2], usw.,
1449 // insgesamt count Digits, und liefert 0 falls alle gleich sind,
1450 // +1 falls zuerst ein xptr[i]>yptr[i] ist,
1451 // -1 falls zuerst ein xptr[i]<yptr[i] ist.
1452   inline cl_signean compare_loop_down (const uintD* xptr, const uintD* yptr, uintC count)
1453     { dotimesC(count,count,
1454         { if (!(*--xptr == *--yptr))
1455             // verschiedene Digits gefunden
1456             return (*xptr > *yptr ? signean_plus : signean_minus);
1457         });
1458       return signean_null; // alle Digits gleich
1459     }
1460
1461 #endif
1462
1463 #ifndef ADDSUB_LOOPS
1464
1465 // Additionsschleife:
1466 // übertrag = add_loop_up(sourceptr1,sourceptr2,destptr,count);
1467 // addiert count (uintC>=0) Digits aufwärts von sourceptr1, von sourceptr2
1468 // aufwärts nach destptr und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
1469   inline uintD add_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count)
1470     { var uintD source1;
1471       var uintD source2;
1472       if (!(count==0))
1473       do { source1 = *sourceptr1++;
1474            source2 = *sourceptr2++;
1475            *destptr++ = source1 + source2;
1476            if (source1 > (uintD)(~source2)) goto carry_1;
1477            carry_0:
1478            count--;
1479          }
1480          until (count==0);
1481       return 0;
1482       do { source1 = *sourceptr1++;
1483            source2 = *sourceptr2++;
1484            *destptr++ = source1 + source2 + 1;
1485            if (source1 < (uintD)(~source2)) goto carry_0;
1486            carry_1:
1487            count--;
1488          }
1489          until (count==0);
1490       return 1;
1491     }
1492
1493 // Additionsschleife:
1494 // übertrag = addto_loop_up(sourceptr,destptr,count);
1495 // addiert count (uintC>=0) Digits aufwärts von sourceptr, von destptr
1496 // aufwärts nach destptr und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
1497   inline uintD addto_loop_up (const uintD* sourceptr, uintD* destptr, uintC count)
1498     { var uintD source1;
1499       var uintD source2;
1500       if (!(count==0))
1501       do { source1 = *sourceptr++;
1502            source2 = *destptr;
1503            *destptr++ = source1 + source2;
1504            if (source1 > (uintD)(~source2)) goto carry_1;
1505            carry_0:
1506            count--;
1507          }
1508          until (count==0);
1509       return 0;
1510       do { source1 = *sourceptr++;
1511            source2 = *destptr;
1512            *destptr++ = source1 + source2 + 1;
1513            if (source1 < (uintD)(~source2)) goto carry_0;
1514            carry_1:
1515            count--;
1516          }
1517          until (count==0);
1518       return 1;
1519     }
1520
1521 // Incrementierschleife:
1522 // übertrag = inc_loop_up(ptr,count);
1523 // incrementiert count (uintC>=0) Digits aufwärts von ptr, so lange bis kein
1524 // Übertrag mehr auftritt und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
1525   inline uintD inc_loop_up (uintD* ptr, uintC count)
1526     { dotimesC(count,count,
1527         { if (!( ++(*ptr++) == 0 )) return 0; } // kein weiterer Übertrag
1528         );
1529       return 1; // weiterer Übertrag
1530     }
1531
1532 // Subtraktionsschleife:
1533 // übertrag = sub_loop_up(sourceptr1,sourceptr2,destptr,count);
1534 // subtrahiert count (uintC>=0) Digits aufwärts von sourceptr1, von sourceptr2
1535 // aufwärts nach destptr und liefert den Übertrag (0 oder /=0, was -1 bedeutet).
1536   inline uintD sub_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count)
1537     { var uintD source1;
1538       var uintD source2;
1539       if (!(count==0))
1540       do { source1 = *sourceptr1++;
1541            source2 = *sourceptr2++;
1542            *destptr++ = source1 - source2;
1543            if (source1 < source2) goto carry_1;
1544            carry_0:
1545            count--;
1546          }
1547          until (count==0);
1548       return 0;
1549       do { source1 = *sourceptr1++;
1550            source2 = *sourceptr2++;
1551            *destptr++ = source1 - source2 - 1;
1552            if (source1 > source2) goto carry_0;
1553            carry_1:
1554            count--;
1555          }
1556          until (count==0);
1557       return (uintD)(-1);
1558     }
1559
1560 // Subtraktionsschleife:
1561 // übertrag = subx_loop_up(sourceptr1,sourceptr2,destptr,count,carry);
1562 // subtrahiert count (uintC>=0) Digits aufwärts von sourceptr1 und addiert
1563 // einen Carry (0 oder -1), von sourceptr2 aufwärts nach destptr und
1564 // liefert den Übertrag (0 oder /=0, was -1 bedeutet).
1565   inline uintD subx_loop_up (const uintD* sourceptr1, const uintD* sourceptr2, uintD* destptr, uintC count, uintD carry)
1566     { var uintD source1;
1567       var uintD source2;
1568       if (carry==0)
1569         { if (!(count==0))
1570             do { source1 = *sourceptr1++;
1571                  source2 = *sourceptr2++;
1572                  *destptr++ = source1 - source2;
1573                  if (source1 < source2) goto carry_1;
1574                  carry_0:
1575                  count--;
1576                }
1577                until (count==0);
1578           return 0;
1579         }
1580         else
1581         { if (!(count==0))
1582             do { source1 = *sourceptr1++;
1583                  source2 = *sourceptr2++;
1584                  *destptr++ = source1 - source2 - 1;
1585                  if (source1 > source2) goto carry_0;
1586                  carry_1:
1587                  count--;
1588                }
1589                until (count==0);
1590           return (uintD)(-1);
1591     }   }
1592
1593 // Subtraktionsschleife:
1594 // übertrag = subfrom_loop_up(sourceptr,destptr,count);
1595 // subtrahiert count (uintC>=0) Digits aufwärts von sourceptr, von destptr
1596 // aufwärts nach destptr (dest := dest - source)
1597 // und liefert den Übertrag (0 oder /=0, was -1 bedeutet).
1598   inline uintD subfrom_loop_up (const uintD* sourceptr, uintD* destptr, uintC count)
1599     { var uintD source1;
1600       var uintD source2;
1601       if (!(count==0))
1602       do { source1 = *destptr;
1603            source2 = *sourceptr++;
1604            *destptr++ = source1 - source2;
1605            if (source1 < source2) goto carry_1;
1606            carry_0:
1607            count--;
1608          }
1609          until (count==0);
1610       return 0;
1611       do { source1 = *destptr;
1612            source2 = *sourceptr++;
1613            *destptr++ = source1 - source2 - 1;
1614            if (source1 > source2) goto carry_0;
1615            carry_1:
1616            count--;
1617          }
1618          until (count==0);
1619       return (uintD)(-1);
1620     }
1621
1622 // Decrementierschleife:
1623 // übertrag = dec_loop_up(ptr,count);
1624 // decrementiert count (uintC>=0) Digits aufwärts von ptr, so lange bis kein
1625 // Übertrag mehr auftritt und liefert den Übertrag (0 oder -1).
1626   inline uintD dec_loop_up (uintD* ptr, uintC count)
1627     { dotimesC(count,count,
1628         { if (!( (*ptr++)-- == 0 )) return 0; } // kein weiterer Übertrag
1629         );
1630       return (uintD)(-1); // weiterer Übertrag
1631     }
1632
1633 // Negierschleife:
1634 // übertrag = neg_loop_up(ptr,count);
1635 // negiert count (uintC>=0) Digits aufwärts von ptr,
1636 // und liefert den Übertrag (0 oder -1).
1637   inline uintD neg_loop_up (uintD* ptr, uintC count)
1638     { // erstes Digit /=0 suchen:
1639       until (count==0) { if (!(*ptr == 0)) goto L1; ptr++; count--; }
1640       return 0;
1641       L1: // erstes Digit /=0 gefunden, ab jetzt gibt's Carrys
1642       *ptr = - *ptr; count--; // 1 Digit negieren
1643       dotimesC(count,count, { ptr++; *ptr = ~ *ptr; } ); // alle anderen Digits invertieren
1644       return (uintD)(-1);
1645     }
1646
1647 #endif
1648
1649 #ifndef SHIFT_LOOPS
1650
1651 // Schiebeschleife um 1 Bit nach links:
1652 // übertrag = shift1left_loop_up(ptr,count);
1653 // schiebt count (uintC>=0) Digits aufwärts von ptr um 1 Bit nach links,
1654 // und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
1655   #if HAVE_DD
1656   inline uintD shift1left_loop_up (uintD* ptr, uintC count)
1657     { var uintDD accu = 0;
1658       dotimesC(count,count,
1659         { accu = ((uintDD)(*ptr)<<1)+accu; *ptr++ = lowD(accu);
1660           accu = (uintDD)(highD(accu));
1661         });
1662       return (uintD)accu;
1663     }
1664   #else
1665   inline uintD shift1left_loop_up (uintD* ptr, uintC count)
1666     { var uintD carry = 0;
1667       dotimesC(count,count,
1668         { var uintD accu = *ptr;
1669           *ptr++ = (accu<<1) | carry;
1670           carry = accu>>(intDsize-1);
1671         });
1672       return carry;
1673     }
1674   #endif
1675
1676 // Schiebeschleife um i Bits nach links:
1677 // übertrag = shiftleft_loop_up(ptr,count,i,übertrag_init);
1678 // schiebt count (uintC>=0) Digits aufwärts von ptr um i Bits (0<i<intDsize)
1679 // nach links, schiebt dabei die i Bits aus übertrag_init rechts rein,
1680 // und liefert den Übertrag (was links rauskommt, >=0, <2^i).
1681   #if HAVE_DD
1682   inline uintD shiftleft_loop_up (uintD* ptr, uintC count, uintC i, uintD carry)
1683     { var uintDD accu = (uintDD)carry;
1684       dotimesC(count,count,
1685         { accu = ((uintDD)(*ptr)<<i)+accu; *ptr++ = lowD(accu);
1686           accu = (uintDD)(highD(accu));
1687         });
1688       return (uintD)accu;
1689     }
1690   #else
1691   inline uintD shiftleft_loop_up (uintD* ptr, uintC count, uintC i, uintD carry)
1692     { var uintC j = intDsize-i;
1693       dotimesC(count,count,
1694         { var uintD accu = *ptr;
1695           *ptr++ = (accu<<i) | carry;
1696           carry = accu>>j;
1697         });
1698       return carry;
1699     }
1700   #endif
1701
1702 // Schiebe- und Kopierschleife um i Bits nach links:
1703 // übertrag = shiftleftcopy_loop_up(sourceptr,destptr,count,i);
1704 // kopiert count (uintC>=0) Digits aufwärts von sourceptr nach destptr
1705 // und schiebt sie dabei um i Bits (0<i<intDsize) nach links,
1706 // wobei ganz rechts mit i Nullbits aufgefüllt wird,
1707 // und liefert den Übertrag (was links rauskommt, >=0, <2^i).
1708   #if HAVE_DD
1709   inline uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
1710     { var uintDD accu = 0;
1711       dotimesC(count,count,
1712         { accu = ((uintDD)(*sourceptr++)<<i)+accu; *destptr++ = lowD(accu);
1713           accu = (uintDD)(highD(accu));
1714         });
1715       return (uintD)accu;
1716     }
1717   #else
1718   inline uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
1719     { var uintC j = intDsize-i;
1720       var uintD carry = 0;
1721       dotimesC(count,count,
1722         { var uintD accu = *sourceptr++;
1723           *destptr++ = (accu<<i) | carry;
1724           carry = accu>>j;
1725         });
1726       return carry;
1727     }
1728   #endif
1729
1730 // Schiebeschleife um 1 Bit nach rechts:
1731 // übertrag = shift1right_loop_down(ptr,count,übertrag_init);
1732 // schiebt count (uintC>=0) Digits abwärts von ptr um 1 Bit nach rechts,
1733 // wobei links das Bit übertrag_init (sollte =0 oder =-1 sein) hineingeschoben
1734 // wird, und liefert den Übertrag (0 oder /=0, was 1 bedeutet).
1735   #if HAVE_DD
1736   inline uintD shift1right_loop_down (uintD* ptr, uintC count, uintD carry)
1737     { var uintDD accu = (sintDD)(sintD)carry & ((uintDD)1 << (2*intDsize-1)); // 0 oder bit(2*intDsize-1)
1738       dotimesC(count,count,
1739         { accu = (highlowDD_0(*--ptr)>>1)+accu; *ptr = highD(accu);
1740           accu = highlowDD_0(lowD(accu));
1741         });
1742       return highD(accu);
1743     }
1744   #else
1745   inline uintD shift1right_loop_down (uintD* ptr, uintC count, uintD carry)
1746     { carry = carry << (intDsize-1); // carry zu einem einzigen Bit machen
1747       dotimesC(count,count,
1748         { var uintD accu = *--ptr;
1749           *ptr = (accu >> 1) | carry;
1750           carry = accu << (intDsize-1);
1751         });
1752       return carry;
1753     }
1754   #endif
1755
1756 // Schiebeschleife um i Bits nach rechts:
1757 // übertrag = shiftright_loop_down(ptr,count,i);
1758 // schiebt count (uintC>=0) Digits abwärts von ptr um i Bits (0<i<intDsize)
1759 // nach rechts, wobei links Nullen eingeschoben werden,
1760 // und liefert den Übertrag (was rechts rauskommt, als Bits intDsize-1..intDsize-i).
1761   #if HAVE_DD
1762   inline uintD shiftright_loop_down (uintD* ptr, uintC count, uintC i)
1763     { var uintDD accu = 0;
1764       dotimesC(count,count,
1765         { // Die oberen i Bits von (uintD)accu bilden hier den Übertrag.
1766           accu = highlowDD_0(lowD(accu));
1767           // Die oberen i Bits von (uintDD)accu bilden hier den Übertrag.
1768           accu = (highlowDD_0(*--ptr)>>i)+accu; *ptr = highD(accu);
1769         });
1770       return lowD(accu);
1771     }
1772   #else
1773   inline uintD shiftright_loop_down (uintD* ptr, uintC count, uintC i)
1774     { var uintC j = intDsize-i;
1775       var uintD carry = 0;
1776       dotimesC(count,count,
1777         { var uintD accu = *--ptr;
1778           *ptr = (accu >> i) | carry;
1779           carry = accu << j;
1780         });
1781       return carry;
1782     }
1783   #endif
1784
1785 // Schiebeschleife um i Bits nach rechts:
1786 // übertrag = shiftrightsigned_loop_down(ptr,count,i);
1787 // schiebt count (uintC>0) Digits abwärts von ptr um i Bits (0<i<intDsize)
1788 // nach rechts, wobei links das MSBit ver-i-facht wird,
1789 // und liefert den Übertrag (was rechts rauskommt, als Bits intDsize-1..intDsize-i).
1790   #if HAVE_DD
1791   inline uintD shiftrightsigned_loop_down (uintD* ptr, uintC count, uintC i)
1792     { var uintDD accu = // Übertrag mit i Vorzeichenbits initialisieren
1793                            highlowDD_0(sign_of_sintD((sintD)(ptr[-1])))>>i;
1794       dotimespC(count,count,
1795         { // Die oberen i Bits von (uintD)accu bilden hier den Übertrag.
1796           accu = highlowDD_0(lowD(accu));
1797           // Die oberen i Bits von (uintDD)accu bilden hier den Übertrag.
1798           accu = (highlowDD_0(*--ptr)>>i)+accu; *ptr = highD(accu);
1799         });
1800       return lowD(accu);
1801     }
1802   #else
1803   inline uintD shiftrightsigned_loop_down (uintD* ptr, uintC count, uintC i)
1804     { var uintC j = intDsize-i;
1805       var uintD carry;
1806       { var uintD accu = *--ptr;
1807         *ptr = (sintD)accu >> i;
1808         carry = accu << j;
1809         count--;
1810       }
1811       dotimesC(count,count,
1812         { var uintD accu = *--ptr;
1813           *ptr = (accu >> i) | carry;
1814           carry = accu << j;
1815         });
1816       return carry;
1817     }
1818   #endif
1819
1820 // Schiebe- und Kopier-Schleife um i Bits nach rechts:
1821 // übertrag = shiftrightcopy_loop_down(sourceptr,destptr,count,i,carry);
1822 // kopiert count (uintC>=0) Digits abwärts von sourceptr nach destptr
1823 // und schiebt sie dabei um i Bits (0<i<intDsize) nach rechts, wobei carry
1824 // (sozusagen als sourceptr[0]) die i Bits ganz links bestimmt,
1825 // und liefert den Übertrag (was rechts rauskommt, als Bits intDsize-1..intDsize-i).
1826   #if HAVE_DD
1827   inline uintD shiftrightcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry)
1828     { var uintDD accu = // Übertrag mit carry initialisieren
1829                            highlowDD_0(carry)>>i;
1830       dotimesC(count,count,
1831         { // Die oberen i Bits von (uintD)accu bilden hier den Übertrag.
1832           accu = highlowDD_0(lowD(accu));
1833           // Die oberen i Bits von (uintDD)accu bilden hier den Übertrag.
1834           accu = (highlowDD_0(*--sourceptr)>>i)+accu; *--destptr = highD(accu);
1835         });
1836       return lowD(accu);
1837     }
1838   #else
1839   inline uintD shiftrightcopy_loop_down (const uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry)
1840     { var uintC j = intDsize-i;
1841       carry = carry << j;
1842       dotimesC(count,count,
1843         { var uintD accu = *--sourceptr;
1844           *--destptr = (accu >> i) | carry;
1845           carry = accu << j;
1846         });
1847       return carry;
1848     }
1849   #endif
1850
1851 #endif
1852
1853 #ifndef MUL_LOOPS
1854
1855 // Multiplikations-Einfachschleife:
1856 // Multipliziert eine UDS mit einem kleinen Digit und addiert ein kleines Digit.
1857 // mulusmall_loop_up(digit,ptr,len,newdigit)
1858 // multipliziert die UDS  ptr[0..len-1]  mit digit (>=2, <=36),
1859 // addiert dabei newdigit (>=0, <digit) zur letzten Ziffer,
1860 // und liefert den Carry (>=0, <digit).
1861   #if HAVE_DD
1862   inline uintD mulusmall_loop_up (uintD digit, uintD* ptr, uintC len, uintD newdigit)
1863     { var uintDD carry = newdigit;
1864       dotimesC(len,len,
1865         { // Hier ist 0 <= carry < digit.
1866           carry = carry + muluD(digit,*ptr);
1867           // Hier ist 0 <= carry < 2^intDsize*digit.
1868           *ptr++ = lowD(carry);
1869           carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) < digit
1870         });
1871       return lowD(carry);
1872     }
1873   #else
1874   inline uintD mulusmall_loop_up (uintD digit, uintD* ptr, uintC len, uintD newdigit)
1875     { var uintD carry = newdigit;
1876       dotimesC(len,len,
1877         { // Hier ist 0 <= carry < digit.
1878           var uintD hi;
1879           var uintD lo;
1880           muluD(digit,*ptr,hi=,lo=);
1881           // Hier ist 0 <= 2^intDsize*hi + lo + carry < 2^intDsize*digit.
1882           lo += carry; if (lo < carry) { hi += 1; }
1883           *ptr++ = lo;
1884           carry = hi;
1885         });
1886       return carry;
1887     }
1888   #endif
1889
1890 // Multiplikations-Einfachschleife:
1891 // Multipliziert eine UDS mit einem Digit und legt das Ergebnis in einer
1892 // zweiten UDS ab.
1893 // mulu_loop_up(digit,sourceptr,destptr,len);
1894 // multipliziert die UDS  sourceptr[0..len-1]  (len>0)
1895 // mit dem einzelnen  digit
1896 // und legt das Ergebnis in der UDS  destptr[0..len]  ab.
1897   #if HAVE_DD
1898   inline void mulu_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1899     { var uintDD carry = 0;
1900       dotimespC(len,len,
1901         { // Hier ist carry=digit=0 oder 0 <= carry < digit.
1902           carry = carry + muluD(digit,*sourceptr++);
1903           // Hier ist carry=digit=0 oder 0 <= carry < 2^intDsize*digit.
1904           *destptr++ = lowD(carry);
1905           carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) < digit
1906         });
1907       *destptr++ = lowD(carry);
1908     }
1909   #else
1910   inline void mulu_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1911     { var uintD carry = 0;
1912       dotimespC(len,len,
1913         { // Hier ist carry=digit=0 oder 0 <= carry < digit.
1914           var uintD hi;
1915           var uintD lo;
1916           muluD(digit,*sourceptr++,hi=,lo=);
1917           // Hier ist 0 <= 2^intDsize*hi + lo + carry < 2^intDsize*digit oder hi=lo=carry=digit=0.
1918           lo += carry; if (lo < carry) { hi += 1; }
1919           *destptr++ = lo;
1920           carry = hi;
1921         });
1922       *destptr++ = carry;
1923     }
1924   #endif
1925
1926 // Multiplikations-Einfachschleife mit Akkumulation:
1927 // Multipliziert eine UDS mit einem Digit und addiert das Ergebnis zu einer
1928 // zweiten UDS auf.
1929 // muluadd_loop_up(digit,sourceptr,destptr,len);
1930 // multipliziert die UDS  sourceptr[0..len-1]  (len>0)
1931 // mit dem einzelnen digit, legt das Ergebnis in der UDS  destptr[0..len-1]
1932 // ab und liefert den weiteren Übertrag.
1933   #if HAVE_DD
1934   inline uintD muluadd_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1935     { var uintDD carry = 0;
1936       if (!(digit==0))
1937         { dotimespC(len,len,
1938             { // Hier ist 0 <= carry <= digit.
1939               carry = carry + muluD(digit,*sourceptr++) + (uintDD)*destptr;
1940               // Hier ist 0 <= carry <= 2^intDsize*digit + 2^intDsize-1.
1941               *destptr++ = lowD(carry);
1942               carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) <= digit
1943             });
1944         }
1945       return lowD(carry);
1946     }
1947   #else
1948   inline uintD muluadd_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1949     { var uintD carry = 0;
1950       if (!(digit==0))
1951         { dotimespC(len,len,
1952             { // Hier ist 0 <= carry <= digit.
1953               var uintD hi;
1954               var uintD lo;
1955               muluD(digit,*sourceptr++,hi=,lo=);
1956               // Hier ist 0 <= 2^intDsize*hi + lo + carry + *destptr <= 2^intDsize*digit+2^intDsize-1.
1957               lo += carry; if (lo < carry) { hi += 1; }
1958               carry = *destptr;
1959               lo += carry; if (lo < carry) { hi += 1; }
1960               *destptr++ = lo;
1961               carry = hi;
1962             });
1963         }
1964       return carry;
1965     }
1966   #endif
1967
1968 // Multiplikations-Einfachschleife mit Diminution:
1969 // Multipliziert eine UDS mit einem Digit und subtrahiert das Ergebnis von
1970 // einer zweiten UDS.
1971 // mulusub_loop_up(digit,sourceptr,destptr,len);
1972 // multipliziert die UDS  sourceptr[0..len-1]  (len>0)  mit dem einzelnen
1973 // digit, subtrahiert das Ergebnis von der UDS  destptr[0..len-1]  und liefert
1974 // den weiteren Übertrag (>=0, evtl. von destptr[len] zu subtrahieren).
1975   #if HAVE_DD
1976   inline uintD mulusub_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1977     { var uintDD carry = 0;
1978       if (!(digit==0))
1979         { dotimespC(len,len,
1980             { // Hier ist 0 <= carry <= digit.
1981               carry = carry + muluD(digit,*sourceptr++) + (uintD)(~(*destptr));
1982               // Hier ist 0 <= carry <= 2^intDsize*digit + 2^intDsize-1.
1983               *destptr++ = ~lowD(carry);
1984               carry = (uintDD)highD(carry); // carry := floor(carry/2^intDsize) <= digit
1985               // Hier ist 0 <= carry <= digit.
1986             });
1987           return lowD(carry);
1988         }
1989         else
1990         return 0; // nichts zu subtrahieren -> kein Übertrag
1991     }
1992   #else
1993   inline uintD mulusub_loop_up (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
1994     { var uintD carry = 0;
1995       if (!(digit==0))
1996         { dotimespC(len,len,
1997             { // Hier ist 0 <= carry <= digit.
1998               var uintD hi;
1999               var uintD lo;
2000               muluD(digit,*sourceptr++,hi=,lo=);
2001               // Hier ist 0 <= 2^intDsize*hi + lo + carry + ~(*destptr) <= 2^intDsize*digit+2^intDsize-1.
2002               lo += carry; if (lo < carry) { hi += 1; }
2003               carry = *destptr;
2004               *destptr++ = carry - lo; if (carry < lo) { hi += 1; }
2005               carry = hi;
2006             });
2007           return carry;
2008         }
2009         else
2010         return 0; // nichts zu subtrahieren -> kein Übertrag
2011     }
2012   #endif
2013
2014 #endif
2015
2016 #ifndef DIV_LOOPS
2017
2018 // Divisions-Einfachschleife:
2019 // Dividiert eine UDS durch ein Digit.
2020 // divu_loop_down(digit,ptr,len)
2021 // dividiert die UDS  ptr[-len..-1] durch digit,
2022 // legt das Ergebnis in derselben UDS ab, und liefert den Rest (>=0, <digit).
2023   #if HAVE_DD
2024   inline uintD divu_loop_down (uintD digit, uintD* ptr, uintC len)
2025     { var uintD rest = 0;
2026       dotimesC(len,len,
2027         { --ptr; divuD(highlowDD(rest,*ptr),digit,*ptr =, rest =); }
2028         );
2029       return rest;
2030     }
2031   #else
2032   inline uintD divu_loop_down (uintD digit, uintD* ptr, uintC len)
2033     { var uintD rest = 0;
2034       dotimesC(len,len,
2035         { --ptr; divuD(rest,*ptr,digit,*ptr =, rest =); }
2036         );
2037       return rest;
2038     }
2039   #endif
2040
2041 // Divisions-Einfachschleife:
2042 // Dividiert eine UDS durch ein Digit und legt das Ergebnis in einer
2043 // zweiten UDS ab.
2044 // divucopy_loop_down(digit,sourceptr,destptr,len)
2045 // dividiert die UDS  sourceptr[-len..-1]  durch digit,
2046 // legt das Ergebnis in der UDS  destptr[-len..-1]  ab,
2047 // und liefert den Rest (>=0, <digit).
2048   #if HAVE_DD
2049   inline uintD divucopy_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
2050     { var uintD rest = 0;
2051       dotimesC(len,len,
2052         { divuD(highlowDD(rest,*--sourceptr),digit,*--destptr =, rest =); }
2053         );
2054       return rest;
2055     }
2056   #else
2057   inline uintD divucopy_loop_down (uintD digit, const uintD* sourceptr, uintD* destptr, uintC len)
2058     { var uintD rest = 0;
2059       dotimesC(len,len,
2060         { divuD(rest,*--sourceptr,digit,*--destptr =, rest =); }
2061         );
2062       return rest;
2063     }
2064   #endif
2065
2066 #endif
2067
2068 #endif // !CL_DS_BIG_ENDIAN_P
2069
2070 #if !defined(TEST_LOOPS) && !CL_DS_BIG_ENDIAN_P
2071
2072 // Vergleichsschleife:
2073 // result = compare_loop_up(xptr,yptr,count);
2074 // vergleicht nacheinander xptr[0] mit yptr[0], xptr[1] mit yptr[1], usw.,
2075 // insgesamt count Digits, und liefert 0 falls alle gleich sind,
2076 // +1 falls zuerst ein xptr[i]>yptr[i] ist,
2077 // -1 falls zuerst ein xptr[i]<yptr[i] ist.
2078   inline cl_signean compare_loop_up (const uintD* xptr, const uintD* yptr, uintC count)
2079     { dotimesC(count,count,
2080         { if (!(*xptr++ == *yptr++))
2081             // verschiedene Digits gefunden
2082             return (*--xptr > *--yptr ? signean_plus : signean_minus);
2083         });
2084       return signean_null; // alle Digits gleich
2085     }
2086
2087 #endif
2088
2089 #if !defined(LOG_LOOPS) && !CL_DS_BIG_ENDIAN_P
2090
2091 // XOR-Schleife:
2092 // xor_loop_up(xptr,yptr,count);
2093 // verknüpft count (uintC>=0) Digits aufwärts ab xptr und ab yptr
2094 // mit Ziel ab xptr durch XOR.
2095   inline void xor_loop_up (uintD* xptr, const uintD* yptr, uintC count)
2096     { dotimesC(count,count, { *xptr++ ^= *yptr++; } ); }
2097
2098 #endif
2099
2100 #if !defined(SHIFT_LOOPS) && CL_DS_BIG_ENDIAN_P
2101
2102 // Schiebe- und Kopierschleife um i Bits nach links:
2103 // übertrag = shiftleftcopy_loop_up(sourceptr,destptr,count,i);
2104 // kopiert count (uintC>=0) Digits aufwärts von sourceptr nach destptr
2105 // und schiebt sie dabei um i Bits (0<i<intDsize) nach links,
2106 // wobei ganz rechts mit i Nullbits aufgefüllt wird,
2107 // und liefert den Übertrag (was links rauskommt, >=0, <2^i).
2108   #if HAVE_DD
2109   inline uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
2110     { var uintDD accu = 0;
2111       dotimesC(count,count,
2112         { accu = ((uintDD)(*sourceptr++)<<i)+accu; *destptr++ = lowD(accu);
2113           accu = (uintDD)(highD(accu));
2114         });
2115       return (uintD)accu;
2116     }
2117   #else
2118   inline uintD shiftleftcopy_loop_up (const uintD* sourceptr, uintD* destptr, uintC count, uintC i)
2119     { var uintC j = intDsize-i;
2120       var uintD carry = 0;
2121       dotimesC(count,count,
2122         { var uintD accu = *sourceptr++;
2123           *destptr++ = (accu<<i) | carry;
2124           carry = accu>>j;
2125         });
2126       return carry;
2127     }
2128   #endif
2129
2130 #endif
2131
2132 #if !defined(SHIFT_LOOPS)
2133
2134 // Schiebe- und XOR-Schleife:
2135 // shiftxor_loop_up(xptr,yptr,count,i);
2136 // verknüpft count+1 Digits aufwärts ab xptr mit count Digits aufwärts ab yptr,
2137 // um i Bits verschoben, durch XOR. (count uintC>=0, 0<i<intDsize)
2138   #if HAVE_DD
2139   inline void shiftxor_loop_up (uintD* xptr, const uintD* yptr, uintC count, uintC i)
2140     { if (count > 0)
2141         { var uintD carry = xptr[0];
2142           dotimespC(count,count,
2143             { var uintDD accu = highlowDD(xptr[1],carry);
2144               accu = ((uintDD)(*yptr++)<<i) ^ accu;
2145               *xptr++ = lowD(accu);
2146               carry = highD(accu);
2147             });
2148           *xptr = carry;
2149     }   }
2150   #else
2151   inline void shiftxor_loop_up (uintD* xptr, const uintD* yptr, uintC count, uintC i)
2152     { if (count > 0)
2153         { var uintC j = intDsize-i;
2154           var uintD carry = *xptr;
2155           dotimespC(count,count,
2156             { var uintD accu = *yptr++;
2157               *xptr++ = (accu<<i) ^ carry;
2158               carry = (accu>>j) ^ *xptr;
2159             });
2160           *xptr = carry;
2161     }   }
2162   #endif
2163
2164 #endif
2165
2166
2167 // Endianness independent names for these functions.
2168 #if CL_DS_BIG_ENDIAN_P
2169   #define copy_loop_msp              copy_loop_up
2170   #define copy_loop_lsp              copy_loop_down
2171   #define fill_loop_msp              fill_loop_up
2172   #define fill_loop_lsp              fill_loop_down
2173   #define clear_loop_msp             clear_loop_up
2174   #define clear_loop_lsp             clear_loop_down
2175   #define test_loop_msp              test_loop_up
2176   #define or_loop_msp                or_loop_up
2177   #define xor_loop_msp               xor_loop_up
2178   #define and_loop_msp               and_loop_up
2179   #define eqv_loop_msp               eqv_loop_up
2180   #define nand_loop_msp              nand_loop_up
2181   #define nor_loop_msp               nor_loop_up
2182   #define andc2_loop_msp             andc2_loop_up
2183   #define orc2_loop_msp              orc2_loop_up
2184   #define not_loop_msp               not_loop_up
2185   #define and_test_loop_msp          and_test_loop_up
2186   #define compare_loop_msp           compare_loop_up
2187   #define add_loop_lsp               add_loop_down
2188   #define addto_loop_lsp             addto_loop_down
2189   #define inc_loop_lsp               inc_loop_down
2190   #define sub_loop_lsp               sub_loop_down
2191   #define subx_loop_lsp              subx_loop_down
2192   #define subfrom_loop_lsp           subfrom_loop_down
2193   #define dec_loop_lsp               dec_loop_down
2194   #define neg_loop_lsp               neg_loop_down
2195   #define shift1left_loop_lsp        shift1left_loop_down
2196   #define shiftleft_loop_lsp         shiftleft_loop_down
2197   #define shiftleftcopy_loop_lsp     shiftleftcopy_loop_down
2198   #define shift1right_loop_msp       shift1right_loop_up
2199   #define shiftright_loop_msp        shiftright_loop_up
2200   #define shiftrightsigned_loop_msp  shiftrightsigned_loop_up
2201   #define shiftrightcopy_loop_msp    shiftrightcopy_loop_up
2202   #define mulusmall_loop_lsp         mulusmall_loop_down
2203   #define mulu_loop_lsp              mulu_loop_down
2204   #define muluadd_loop_lsp           muluadd_loop_down
2205   #define mulusub_loop_lsp           mulusub_loop_down
2206   #define divu_loop_msp              divu_loop_up
2207   #define divucopy_loop_msp          divucopy_loop_up
2208 #else
2209   #define copy_loop_msp              copy_loop_down
2210   #define copy_loop_lsp              copy_loop_up
2211   #define fill_loop_msp              fill_loop_down
2212   #define fill_loop_lsp              fill_loop_up
2213   #define clear_loop_msp             clear_loop_down
2214   #define clear_loop_lsp             clear_loop_up
2215   #define test_loop_msp              test_loop_down
2216   #define or_loop_msp                or_loop_down
2217   #define xor_loop_msp               xor_loop_down
2218   #define and_loop_msp               and_loop_down
2219   #define eqv_loop_msp               eqv_loop_down
2220   #define nand_loop_msp              nand_loop_down
2221   #define nor_loop_msp               nor_loop_down
2222   #define andc2_loop_msp             andc2_loop_down
2223   #define orc2_loop_msp              orc2_loop_down
2224   #define not_loop_msp               not_loop_down
2225   #define and_test_loop_msp          and_test_loop_down
2226   #define compare_loop_msp           compare_loop_down
2227   #define add_loop_lsp               add_loop_up
2228   #define addto_loop_lsp             addto_loop_up
2229   #define inc_loop_lsp               inc_loop_up
2230   #define sub_loop_lsp               sub_loop_up
2231   #define subx_loop_lsp              subx_loop_up
2232   #define subfrom_loop_lsp           subfrom_loop_up
2233   #define dec_loop_lsp               dec_loop_up
2234   #define neg_loop_lsp               neg_loop_up
2235   #define shift1left_loop_lsp        shift1left_loop_up
2236   #define shiftleft_loop_lsp         shiftleft_loop_up
2237   #define shiftleftcopy_loop_lsp     shiftleftcopy_loop_up
2238   #define shift1right_loop_msp       shift1right_loop_down
2239   #define shiftright_loop_msp        shiftright_loop_down
2240   #define shiftrightsigned_loop_msp  shiftrightsigned_loop_down
2241   #define shiftrightcopy_loop_msp    shiftrightcopy_loop_down
2242   #define mulusmall_loop_lsp         mulusmall_loop_up
2243   #define mulu_loop_lsp              mulu_loop_up
2244   #define muluadd_loop_lsp           muluadd_loop_up
2245   #define mulusub_loop_lsp           mulusub_loop_up
2246   #define divu_loop_msp              divu_loop_down
2247   #define divucopy_loop_msp          divucopy_loop_down
2248 #endif
2249
2250 // Endianness independent loops where the direction doesn't matter.
2251 #if CL_DS_BIG_ENDIAN_P
2252   #define DS_clear_loop(MSDptr,len,LSDptr)  (void)clear_loop_up(MSDptr,len)
2253   #define DS_test_loop(MSDptr,len,LSDptr)  test_loop_up(MSDptr,len)
2254 #else
2255   #define DS_clear_loop(MSDptr,len,LSDptr)  (void)clear_loop_up(LSDptr,len)
2256   #define DS_test_loop(MSDptr,len,LSDptr)  test_loop_up(LSDptr,len)
2257 #endif
2258
2259
2260 // Umwandlungsroutinen Digit-Sequence-Teil <--> Longword:
2261
2262 // get_32_Dptr(ptr)
2263 //   holt die nächsten 32 Bits aus den 32/intDsize Digits ab ptr.
2264 // set_32_Dptr(ptr,wert);
2265 //   speichert den Wert wert (32 Bits) in die 32/intDsize Digits ab ptr.
2266 // get_max32_Dptr(count,ptr)
2267 //   holt die nächsten count Bits aus den ceiling(count/intDsize) Digits ab ptr.
2268 // set_max32_Dptr(count,ptr,wert)
2269 //   speichert wert (count Bits) in die ceiling(count/intDsize) Digits ab ptr.
2270 // Jeweils ptr eine Variable vom Typ uintD*,
2271 //         wert eine Variable vom Typ uint32,
2272 //         count eine Variable oder constant-expression mit Wert >=0, <=32.
2273   #if (intDsize==32)
2274     inline uint32 get_32_Dptr (const uintD* ptr)
2275     {
2276         return mspref(ptr,0);
2277     }
2278     inline void set_32_Dptr (uintD* ptr, uint32 wert)
2279     {
2280         mspref(ptr,0) = wert;
2281     }
2282     inline uint32 get_max32_Dptr (uintC count, const uintD* ptr)
2283     {
2284         return count==0 ? 0 :
2285                           mspref(ptr,0);
2286     }
2287     inline void set_max32_Dptr (uintC count, uintD* ptr, uint32 wert)
2288     {
2289         if (count==0) return;
2290         mspref(ptr,0) = wert; return;
2291     }
2292   #endif
2293   #if (intDsize==16)
2294     inline uint32 get_32_Dptr (const uintD* ptr)
2295     {
2296         return ((uint32)mspref(ptr,0)<<16) | (uint32)mspref(ptr,1);
2297     }
2298     inline void set_32_Dptr (uintD* ptr, uint32 wert)
2299     {
2300         mspref(ptr,0) = (uintD)(wert>>16); mspref(ptr,1) = (uintD)wert;
2301     }
2302     inline uint32 get_max32_Dptr (uintC count, const uintD* ptr)
2303     {
2304         return count==0 ? 0 :
2305                count<=16 ? mspref(ptr,0) :
2306                            ((uint32)mspref(ptr,0)<<16) | (uint32)mspref(ptr,1);
2307     }
2308     inline void set_max32_Dptr (uintC count, uintD* ptr, uint32 wert)
2309     {
2310         if (count==0) return;
2311         if (count<=16) { mspref(ptr,0) = (uintD)wert; return; }
2312         mspref(ptr,0) = (uintD)(wert>>16); mspref(ptr,1) = (uintD)wert; return;
2313     }
2314   #endif
2315   #if (intDsize==8)
2316     inline uint32 get_32_Dptr (const uintD* ptr)
2317     {
2318         return ((((((uint32)mspref(ptr,0) <<8) | (uint32)mspref(ptr,1)) <<8) | (uint32)mspref(ptr,2)) <<8) | (uint32)mspref(ptr,3);
2319     }
2320     inline void set_32_Dptr (uintD* ptr, uint32 wert)
2321     {
2322         mspref(ptr,0) = (uintD)(wert>>24); mspref(ptr,1) = (uintD)(wert>>16); mspref(ptr,2) = (uintD)(wert>>8); mspref(ptr,3) = (uintD)wert;
2323     }
2324     inline uint32 get_max32_Dptr (uintC count, const uintD* ptr)
2325     {
2326         return count==0 ? 0 :
2327                count<=8 ? mspref(ptr,0) :
2328                count<=16 ? ((uint32)mspref(ptr,0)<<8) | (uint32)mspref(ptr,1) :
2329                count<=24 ? ((((uint32)mspref(ptr,0)<<8) | (uint32)mspref(ptr,1))<<8) | (uint32)mspref(ptr,2) :
2330                            ((((((uint32)mspref(ptr,0)<<8) | (uint32)mspref(ptr,1))<<8) | (uint32)mspref(ptr,2))<<8) | (uint32)mspref(ptr,3);
2331     }
2332     inline void set_max32_Dptr (uintC count, uintD* ptr, uint32 wert)
2333     {
2334         if (count==0) return;
2335         if (count<=8) { mspref(ptr,0) = (uintD)wert; return; }
2336         if (count<=16) { mspref(ptr,0) = (uintD)(wert>>8); mspref(ptr,1) = (uintD)wert; return; }
2337         if (count<=24) { mspref(ptr,0) = (uintD)(wert>>16); mspref(ptr,1) = (uintD)(wert>>8); mspref(ptr,2) = (uintD)wert; return; }
2338         mspref(ptr,0) = (uintD)(wert>>24); mspref(ptr,1) = (uintD)(wert>>16); mspref(ptr,2) = (uintD)(wert>>8); mspref(ptr,3) = (uintD)wert; return;
2339     }
2340   #endif
2341
2342 #if (cl_word_size==64)
2343 // get_64_Dptr(ptr)
2344 //   holt die nächsten 64 Bits aus den 64/intDsize Digits ab ptr.
2345 // set_64_Dptr(ptr,wert);
2346 //   speichert den Wert wert (64 Bits) in die 64/intDsize Digits ab ptr.
2347 // get_max64_Dptr(count,ptr)
2348 //   holt die nächsten count Bits aus den ceiling(count/intDsize) Digits ab ptr.
2349 // set_max64_Dptr(count,ptr,wert)
2350 //   speichert wert (count Bits) in die ceiling(count/intDsize) Digits ab ptr.
2351 // Jeweils ptr eine Variable vom Typ uintD*,
2352 //         wert eine Variable vom Typ uint64,
2353 //         count eine Variable oder constant-expression mit Wert >=0, <=64.
2354   #if (intDsize==64)
2355     inline uint64 get_64_Dptr (const uintD* ptr)
2356     {
2357         return mspref(ptr,0);
2358     }
2359     inline void set_64_Dptr (uintD* ptr, uint64 wert)
2360     {
2361         mspref(ptr,0) = wert;
2362     }
2363     inline uint64 get_max64_Dptr (uintC count, const uintD* ptr)
2364     {
2365         return count==0 ? 0 : mspref(ptr,0);
2366     }
2367     inline void set_max64_Dptr (uintC count, uintD* ptr, uint64 wert)
2368     {
2369         if (count==0) return;
2370         mspref(ptr,0) = wert; return;
2371     }
2372   #else // (intDsize<=32)
2373     inline uint64 get_64_Dptr (const uintD* ptr)
2374     {
2375         return ((uint64)get_32_Dptr(ptr) << 32) | (uint64)get_32_Dptr(ptr mspop 32/intDsize);
2376     }
2377     inline void set_64_Dptr (uintD* ptr, uint64 wert)
2378     {
2379         set_32_Dptr(ptr,(uint32)(wert>>32));
2380         set_32_Dptr(ptr mspop 32/intDsize,(uint32)wert);
2381     }
2382     inline uint64 get_max64_Dptr (uintC count, const uintD* ptr)
2383     {
2384         return count==0 ? 0 :
2385                count<=32 ? (uint64)get_max32_Dptr(count,ptr) :
2386                            ((uint64)get_max32_Dptr(count-32,ptr) << 32) | (uint64)get_32_Dptr(ptr mspop ceiling(count-32,intDsize));
2387     }
2388     inline void set_max64_Dptr (uintC count, uintD* ptr, uint64 wert)
2389     {
2390         if (count==0) return;
2391         if (count<=32) { set_max32_Dptr(count,ptr,(uint32)wert); return; }
2392         set_max32_Dptr(count-32,ptr,(uint32)(wert>>32));
2393         set_32_Dptr(ptr mspop ceiling(count-32,intDsize),(uint32)wert); return;
2394     }
2395   #endif
2396 #endif
2397
2398 // get_uint1D_Dptr(ptr)  holt 1 Digit (unsigned) ab ptr
2399 // get_uint2D_Dptr(ptr)  holt 2 Digits (unsigned) ab ptr
2400 // get_uint3D_Dptr(ptr)  holt 3 Digits (unsigned) ab ptr
2401 // get_uint4D_Dptr(ptr)  holt 4 Digits (unsigned) ab ptr
2402 // get_sint1D_Dptr(ptr)  holt 1 Digit (signed) ab ptr
2403 // get_sint2D_Dptr(ptr)  holt 2 Digits (signed) ab ptr
2404 // get_sint3D_Dptr(ptr)  holt 3 Digits (signed) ab ptr
2405 // get_sint4D_Dptr(ptr)  holt 4 Digits (signed) ab ptr
2406 // Jeweils ptr eine Variable vom Typ uintD*.
2407 // NB: Bei intDsize==64 sind diese Funktionen nur sehr bedingt tauglich.
2408   inline uint32 get_uint1D_Dptr (const uintD* ptr)
2409   {
2410         return lspref(ptr,0);
2411   }
2412   inline sint32 get_sint1D_Dptr (const uintD* ptr)
2413   {
2414         return (sint32)(sintD)lspref(ptr,0);
2415   }
2416   #if (intDsize < 32)
2417   inline uint32 get_uint2D_Dptr (const uintD* ptr)
2418   {
2419         return ((uint32)lspref(ptr,1) << intDsize) | (uint32)lspref(ptr,0);
2420   }
2421   inline sint32 get_sint2D_Dptr (const uintD* ptr)
2422   {
2423         return ((uint32)(sint32)(sintD)lspref(ptr,1) << intDsize) | (uint32)lspref(ptr,0);
2424   }
2425   #else
2426   #define get_uint2D_Dptr(ptr)  get_uint1D_Dptr(ptr)
2427   #define get_sint2D_Dptr(ptr)  (sint32)get_uint2D_Dptr(ptr)
2428   #endif
2429   #if (intDsize < 16)
2430   inline uint32 get_uint3D_Dptr (const uintD* ptr)
2431   {
2432         return ((((uint32)lspref(ptr,2) << intDsize) | (uint32)lspref(ptr,1)) << intDsize) | (uint32)lspref(ptr,0);
2433   }
2434   inline sint32 get_sint3D_Dptr (const uintD* ptr)
2435   {
2436         return ((((uint32)(sint32)(sintD)lspref(ptr,2) << intDsize) | (uint32)lspref(ptr,1)) << intDsize) | (uint32)lspref(ptr,0);
2437   }
2438   inline uint32 get_uint4D_Dptr (const uintD* ptr)
2439   {
2440         return ((((((uint32)lspref(ptr,3) << intDsize) | (uint32)lspref(ptr,2)) << intDsize) | (uint32)lspref(ptr,1)) << intDsize) | (uint32)lspref(ptr,0);
2441   }
2442   inline sint32 get_sint4D_Dptr (const uintD* ptr)
2443   {
2444         return ((((((uint32)(sint32)(sintD)lspref(ptr,3) << intDsize) | (uint32)lspref(ptr,2)) << intDsize) | (uint32)lspref(ptr,1)) << intDsize) | (uint32)lspref(ptr,0);
2445   }
2446   #else
2447   #define get_uint3D_Dptr(ptr)  get_uint2D_Dptr(ptr)
2448   #define get_sint3D_Dptr(ptr)  (sint32)get_uint3D_Dptr(ptr)
2449   #define get_uint4D_Dptr(ptr)  get_uint2D_Dptr(ptr)
2450   #define get_sint4D_Dptr(ptr)  (sint32)get_uint4D_Dptr(ptr)
2451   #endif
2452
2453
2454 // NUM_STACK ist eine Art Zahlen-Stack-Pointer.
2455 // Verwendung:
2456 //   {CL_ALLOCA_STACK;
2457 //    ...
2458 //    num_stack_alloc(...);
2459 //    ...
2460 //    num_stack_array(...);
2461 //    ...
2462 //   }
2463 // CL_ALLOCA_STACK rettet den aktuellen Wert von NUM_STACK.
2464 // Dann darf beliebig oft mit num_stack_alloc/num_stack_array Platz auf dem
2465 // Zahlen-Stack belegt werden.
2466 // Beim Ende des Blocks wird NUM_STACK wieder auf den vorigen Wert gesetzt,
2467 // und der Platz gilt als wieder freigegeben.
2468 // In jeder C-Funktion sollte CL_ALLOCA_STACK nur einmal aufgerufen werden.
2469 // Wegen eines GCC-Bugs sollten Funktionen, die diese Macros benutzen,
2470 // nicht inline deklariert sein.
2471
2472 // num_stack_array(need, low_addr = , high_addr = );
2473 // num_stack_small_array(need, low_addr = , high_addr = );
2474 // belegt need Digits auf dem Zahlen-Stack und legt die untere Grenze des
2475 // allozierten Bereichs in low_addr und die obere Grenze in high_addr ab.
2476 // Jedes von beiden ist optional.
2477
2478 // num_stack_alloc(need, MSDptr = , LSDptr = );
2479 // num_stack_small_alloc(need, MSDptr = , LSDptr = );
2480 // belegt need Digits auf dem Zahlen-Stack und legt den MSDptr und den
2481 // LSDptr ab. Jedes von beiden ist optional.
2482
2483 // num_stack_alloc_1(need, MSDptr = , LSDptr = );
2484 // num_stack_small_alloc_1(need, MSDptr = , LSDptr = );
2485 // wie num_stack_alloc, nur daß unterhalb von MSDptr noch ein Digit Platz
2486 // zusätzlich belegt wird.
2487
2488 #define num_stack_array(need,low_zuweisung,high_zuweisung)  \
2489   {var uintL __need = (uintL)(need);                            \
2490    var uintD* __array = cl_alloc_array(uintD,__need);           \
2491    unused (low_zuweisung &__array[0]); unused (high_zuweisung &__array[__need]); \
2492   }
2493 #define num_stack_small_array(need,low_zuweisung,high_zuweisung)  \
2494   {var uintL __need = (uintL)(need);                            \
2495    var uintD* __array = cl_small_alloc_array(uintD,__need);     \
2496    unused (low_zuweisung &__array[0]); unused (high_zuweisung &__array[__need]); \
2497   }
2498 #if CL_DS_BIG_ENDIAN_P
2499   #define num_stack_alloc(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2500     num_stack_array(need,MSDptr_zuweisung,LSDptr_zuweisung)
2501   #define num_stack_small_alloc(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2502     num_stack_small_array(need,MSDptr_zuweisung,LSDptr_zuweisung)
2503   #define num_stack_alloc_1(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2504     num_stack_array((uintL)(need)+1,MSDptr_zuweisung 1 + ,LSDptr_zuweisung)
2505   #define num_stack_small_alloc_1(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2506     num_stack_small_array((uintL)(need)+1,MSDptr_zuweisung 1 + ,LSDptr_zuweisung)
2507 #else
2508   #define num_stack_alloc(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2509     num_stack_array(need,LSDptr_zuweisung,MSDptr_zuweisung)
2510   #define num_stack_small_alloc(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2511     num_stack_small_array(need,LSDptr_zuweisung,MSDptr_zuweisung)
2512   #define num_stack_alloc_1(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2513     num_stack_array((uintL)(need)+1,LSDptr_zuweisung,MSDptr_zuweisung -1 + )
2514   #define num_stack_small_alloc_1(need,MSDptr_zuweisung,LSDptr_zuweisung)  \
2515     num_stack_small_array((uintL)(need)+1,LSDptr_zuweisung,MSDptr_zuweisung -1 + )
2516 #endif
2517
2518
2519 // Macro: In der DS MSDptr/len/LSDptr wird eine 1 unterhalb des Pointers ptr
2520 // addiert. Unterhalb von MSDptr muß 1 Digit Platz sein.
2521 // Dabei ist  ptr - MSDptr = count  und  0 < count <= len .
2522 // Eventuell wird MSDptr erniedrigt und len erhöht.
2523   #define DS_1_plus(ptr,count)  \
2524     {var uintD* ptr_from_DS_1_plus = (ptr);                             \
2525      var uintC count_from_DS_1_plus = (count);                          \
2526      loop { if (--count_from_DS_1_plus==0) /* Zähler erniedrigen      */\
2527               { /* Beim Most Significant Digit angelangt              */\
2528                 lsprefnext(ptr_from_DS_1_plus) += 1;                    \
2529                 /* jetzt ist ptr_from_DS_1_plus = MSDptr              */\
2530                 if (mspref(ptr_from_DS_1_plus,0) == (uintD)bit(intDsize-1)) \
2531                   { /* 7FFF + 1 muß zu 00008000 werden:               */\
2532                     lsprefnext(MSDptr) = 0;                             \
2533                     len++;                                              \
2534                   }                                                     \
2535                 break;                                                  \
2536               }                                                         \
2537             if (!((lsprefnext(ptr_from_DS_1_plus) += 1) == 0)) /* weiterincrementieren */\
2538               break; /* kein weiterer Übertrag -> Schleife abbrechen  */\
2539     }     }
2540
2541 // Macro: In der DS MSDptr/len/LSDptr wird eine 1 unterhalb des Pointers ptr
2542 // subtrahiert. Unterhalb von MSDptr muß 1 Digit Platz sein.
2543 // Dabei ist  ptr - MSDptr = count  und  0 < count <= len .
2544 // Eventuell wird MSDptr erniedrigt und len erhöht.
2545   #define DS_minus1_plus(ptr,count)  \
2546     {var uintD* ptr_from_DS_minus1_plus = (ptr);                        \
2547      var uintC count_from_DS_minus1_plus = (count);                     \
2548      loop { if (--count_from_DS_minus1_plus==0) /* Zähler erniedrigen */\
2549               { /* Beim Most Significant Digit angelangt              */\
2550                 lsprefnext(ptr_from_DS_minus1_plus) -= 1;               \
2551                 /* jetzt ist ptr_from_DS_minus1_plus = MSDptr         */\
2552                 if (mspref(ptr_from_DS_minus1_plus,0) == (uintD)bit(intDsize-1)-1) \
2553                   { /* 8000 - 1 muß zu FFFF7FFF werden:               */\
2554                     lsprefnext(MSDptr) = (uintD)(-1);                   \
2555                     len++;                                              \
2556                   }                                                     \
2557                 break;                                                  \
2558               }                                                         \
2559             if (!((sintD)(lsprefnext(ptr_from_DS_minus1_plus) -= 1) == -1)) /* weiterdecrementieren */\
2560               break; /* kein weiterer Übertrag -> Schleife abbrechen  */\
2561     }     }
2562
2563
2564 // Multiplikations-Doppelschleife:
2565 // Multipliziert zwei UDS und legt das Ergebnis in einer dritten UDS ab.
2566 // cl_UDS_mul(sourceptr1,len1,sourceptr2,len2,destptr);
2567 // multipliziert die UDS  sourceptr1[-len1..-1]  (len1>0)
2568 //           mit der UDS  sourceptr2[-len1..-1]  (len2>0)
2569 // und legt das Ergebnis in der UDS  destptr[-len..-1]  (len=len1+len2) ab.
2570 // Unterhalb von destptr werden len Digits Platz benötigt.
2571 extern void cl_UDS_mul (const uintD* sourceptr1, uintC len1,
2572                         const uintD* sourceptr2, uintC len2,
2573                         uintD* destptr);
2574 // Spezialfall sourceptr1 == sourceptr2 && len1 == len2.
2575 extern void cl_UDS_mul_square (const uintD* sourceptr, uintC len,
2576                                uintD* destptr);
2577
2578 // Multipliziert zwei Unsigned-Digit-sequences.
2579 // UDS_UDS_mul_UDS(len1,LSDptr1, len2,LSDptr2, MSDptr=,len=,LSDptr=);
2580 // multipliziert die UDS ../len1/LSDptr1 und ../len2/LSDptr2.
2581 // Dabei sollte len1>0 und len2>0 sein.
2582 // Ergebnis ist die UDS MSDptr/len/LSDptr, mit len=len1+len2, im Stack.
2583 // Dabei wird num_stack erniedrigt.
2584   #define UDS_UDS_mul_UDS(len1,LSDptr1,len2,LSDptr2, MSDptr_zuweisung,len_zuweisung,LSDptr_zuweisung)  \
2585     var uintL CONCAT(len_from_UDSmul_,__LINE__) = (uintL)(len1) + (uintL)(len2); \
2586     var uintD* CONCAT(LSDptr_from_UDSmul_,__LINE__);                            \
2587     unused (len_zuweisung CONCAT(len_from_UDSmul_,__LINE__));                   \
2588     num_stack_alloc(CONCAT(len_from_UDSmul_,__LINE__),MSDptr_zuweisung,LSDptr_zuweisung CONCAT(LSDptr_from_UDSmul_,__LINE__) =); \
2589     cl_UDS_mul((LSDptr1),(len1),(LSDptr2),(len2),CONCAT(LSDptr_from_UDSmul_,__LINE__));
2590
2591 // Multipliziert zwei Digit-sequences.
2592 // DS_DS_mul_DS(MSDptr1,len1,LSDptr1, MSDptr2,len2,LSDptr2, MSDptr=,len=,LSDptr=);
2593 // multipliziert die DS MSDptr1/len1/LSDptr1 und MSDptr2/len2/LSDptr2.
2594 // Dabei sollte len1>0 und len2>0 sein, und beide DS sollten /= 0 sein.
2595 // Alles sollten Variablen sein!
2596 // Ergebnis ist die DS MSDptr/len/LSDptr, mit len=len1+len2, im Stack.
2597 // Dabei wird num_stack erniedrigt.
2598   // Methode:
2599   // Erst unsigned multiplizieren. Dann bis zu zwei Subtraktionen.
2600   // Sei b=2^intDsize, k=len1, l=len2, n=DS1, m=DS2.
2601   // Gesucht ist n * m.
2602   // Wir errechnen erst das unsigned-product p (mod b^(k+l)).
2603   // n>0, m>0: p = n*m,             n*m = p
2604   // n<0, m>0: p = (n+b^k)*m,       n*m + b^(k+l) = p - b^k * m (mod b^(k+l)).
2605   // n>0, m<0: p = n*(m+b^l),       n*m + b^(k+l) = p - b^l * n (mod b^(k+l)).
2606   // n<0, m<0: p = (n+b^k)*(m+b^l),
2607   //           n*m = p - b^k * (m+b^l) - b^l * (n+b^k) (mod b^(k+l)).
2608   #define DS_DS_mul_DS(MSDptr1,len1,LSDptr1,MSDptr2,len2,LSDptr2, MSDptr_zuweisung,len_zuweisung,LSDptr_zuweisung)  \
2609     var uintD* MSDptr0;                                                 \
2610     var uintD* LSDptr0;                                                 \
2611     var uintL len_from_DSmal = (uintL)(len1) + (uintL)(len2);           \
2612     unused (len_zuweisung len_from_DSmal);                              \
2613     num_stack_alloc(len_from_DSmal,MSDptr_zuweisung MSDptr0 =,LSDptr_zuweisung LSDptr0 =); \
2614     var uintD MSD1_from_DSmal = mspref(MSDptr1,0);                      \
2615     var uintD MSD2_from_DSmal = mspref(MSDptr2,0);                      \
2616     var uintL len1_from_DSmal = (len1);                                 \
2617     var uintL len2_from_DSmal = (len2);                                 \
2618     if (MSD1_from_DSmal==0) { msprefnext(MSDptr0) = 0; len1_from_DSmal--; } \
2619     if (MSD2_from_DSmal==0) { msprefnext(MSDptr0) = 0; len2_from_DSmal--; } \
2620     cl_UDS_mul((LSDptr1),len1_from_DSmal,(LSDptr2),len2_from_DSmal,LSDptr0); \
2621     if ((sintD)MSD1_from_DSmal < 0) /* n<0 ?                          */\
2622       /* muß m bzw. m+b^l subtrahieren, um k Digits verschoben:       */\
2623       { subfrom_loop_lsp(LSDptr2,LSDptr0 lspop len1,len2); }            \
2624     if ((sintD)MSD2_from_DSmal < 0) /* m<0 ?                          */\
2625       /* muß n bzw. n+b^k subtrahieren, um l Digits verschoben:       */\
2626       { subfrom_loop_lsp(LSDptr1,LSDptr0 lspop len2,len1); }
2627
2628
2629 // Dividiert zwei Unsigned Digit sequences durcheinander.
2630 // UDS_divide(a_MSDptr,a_len,a_LSDptr, b_MSDptr,b_len,b_LSDptr, &q,&r);
2631 // Die UDS a = a_MSDptr/a_len/a_LSDptr (a>=0) wird durch
2632 // die UDS b = b_MSDptr/b_len/b_LSDptr (b>=0) dividiert:
2633 // a = q * b + r mit 0 <= r < b. Bei b=0 Error.
2634 // q der Quotient, r der Rest.
2635 // q = q_MSDptr/q_len/q_LSDptr, r = r_MSDptr/r_len/r_LSDptr beides
2636 // Normalized Unsigned Digit sequences.
2637 // Vorsicht: q_LSDptr <= r_MSDptr,
2638 //           Vorzeichenerweiterung von r kann q zerstören!
2639 //           Vorzeichenerweiterung von q ist erlaubt.
2640 // a und b werden nicht modifiziert.
2641 // num_stack wird erniedrigt.
2642   #define UDS_divide(a_MSDptr,a_len,a_LSDptr,b_MSDptr,b_len,b_LSDptr,q_,r_)  \
2643     /* Platz fürs Ergebnis machen. Brauche maximal a_len+1 Digits.    */\
2644     var uintC _a_len = (a_len);                                         \
2645     var uintD* roomptr; num_stack_alloc_1(_a_len+1,roomptr=,);          \
2646     cl_UDS_divide(a_MSDptr,_a_len,a_LSDptr,b_MSDptr,b_len,b_LSDptr,roomptr,q_,r_);
2647   extern void cl_UDS_divide (const uintD* a_MSDptr, uintC a_len, const uintD* a_LSDptr,
2648                              const uintD* b_MSDptr, uintC b_len, const uintD* b_LSDptr,
2649                              uintD* roomptr, DS* q_, DS* r_);
2650
2651
2652 // Bildet zu einer Unsigned Digit sequence a die Wurzel
2653 // (genauer: Gaußklammer aus Wurzel aus a).
2654 // UDS_sqrt(a_MSDptr,a_len,a_LSDptr, &b, squarep=)
2655 // > a_MSDptr/a_len/a_LSDptr: eine UDS
2656 // < NUDS b: Gaußklammer der Wurzel aus a
2657 // < squarep: cl_true falls a = b^2, cl_false falls b^2 < a < (b+1)^2.
2658 // a wird nicht modifiziert.
2659 // Vorzeichenerweiterung von b ist erlaubt.
2660 // num_stack wird erniedrigt.
2661   #define UDS_sqrt(a_MSDptr,a_len,a_LSDptr,b_,squarep_zuweisung)  \
2662     { /* ceiling(a_len,2) Digits Platz fürs Ergebnis machen:          */\
2663       var uintC _a_len = (a_len);                                       \
2664       num_stack_alloc_1(ceiling(_a_len,2),(b_)->MSDptr=,);              \
2665       squarep_zuweisung cl_UDS_sqrt(a_MSDptr,_a_len,a_LSDptr,b_);       \
2666     }
2667   extern cl_boolean cl_UDS_sqrt (const uintD* a_MSDptr, uintC a_len, const uintD* a_LSDptr, DS* b_);
2668
2669
2670 // Auxiliary function for approximately computing 1/x
2671 // using Newton iteration.
2672   extern void cl_UDS_recip (const uintD* a_MSDptr, uintC a_len,
2673                             uintD* b_MSDptr, uintC b_len);
2674
2675 // Auxiliary function for approximately computing 1/sqrt(x)
2676 // using Newton iteration.
2677   extern void cl_UDS_recipsqrt (const uintD* a_MSDptr, uintC a_len,
2678                                 uintD* b_MSDptr, uintC b_len);
2679
2680 }  // namespace cln
2681
2682 #endif /* _CL_DS_H */