]> www.ginac.de Git - cln.git/blob - src/integer/bitwise/cl_I_ash.cc
bde719bf8cd50b623f53ffa1c141a51ba6046511
[cln.git] / src / integer / bitwise / cl_I_ash.cc
1 // ash().
2
3 // General includes.
4 #include "cl_sysdep.h"
5
6 // Specification.
7 #include "cln/integer.h"
8
9
10 // Implementation.
11
12 #include "cl_I.h"
13 #include "cl_DS.h"
14 #include "cl_I_ash.h"
15
16 namespace cln {
17
18 const cl_I ash (const cl_I& x, sintL y)
19 {
20     // Methode:
21     // x = 0 -> 0 als Ergebnis
22     // y = 0 -> x als Ergebnis
23     // y > 0 -> y = intDsize*k + i, j=k+(1 falls i>0, 0 falls i=0).
24     //          j Wörter mehr reservieren, k Nullwörter, dann übertragen,
25     //          bei i>0: um i Bits links schieben (i=1 geht einfacher).
26     // y < 0 -> y <= - intDsize * (Länge(A0) in Digits) -> Ergebnis = 0 oder -1.
27     //          Sonst: -y = intDsize*k + i mit k<Länge(A0).
28     //                  Übertrage die (Länge(A0)-k) MSDigits,
29     //                  falls i>0: schiebe sie um i Bits nach rechts (i=1 geht einfacher).
30         if (zerop(x))
31                 return 0;               // x=0 -> 0 als Ergebnis
32         if (y == 0)
33                 return x;               // y=0 -> x als Ergebnis
34         CL_ALLOCA_STACK;
35         if (y >= 0) {
36                 // y>0
37                 var uintL y_ = (uintL)y;
38                 var uintL i = y_%intDsize; // i = y mod intDsize, >=0, <intDsize
39                 var uintL k = floor(y_,intDsize); // k = y div intDsize, >=0, <2^intCsize
40                 var uintD* LSDptr;
41                 var uintC len;
42                 var const uintD* x_LSDptr;
43                 I_to_NDS_nocopy(x, ,len=,x_LSDptr=,cl_false,); // DS zu x bilden.
44                 if (k >= (uintC)(~(uintC)len)) // kann len+k+1 Überlauf geben?
45                         { cl_ash_error(y); } // ja -> Fehler
46                 num_stack_alloc_1(len+k,,LSDptr=);
47                 LSDptr = clear_loop_lsp(LSDptr,k); // k Nulldigits
48                {var uintD* MSDptr = copy_loop_lsp(x_LSDptr,LSDptr,len);
49                 // Nun ist MSDptr/len/LSDptr die DS zu x.
50                 // Oberhalb von ihr liegen k Nulldigits, unterhalb ist 1 Digit Platz.
51                 // MSDptr/len+k/.. ist jetzt die Gesamt-DS.
52                 // Noch um i Bits nach links schieben:
53                 if (!(i==0)) // Bei i>0
54                   { // noch ein weiteres Digit dazunehmen (Vorzeichen)
55                     {var uintD sign = sign_of_sintD(mspref(MSDptr,0));
56                      lsprefnext(MSDptr) = sign;
57                      len++;
58                     }
59                     // Schiebeschleife: die unteren len Digits um i Bits schieben
60                     if (i==1)
61                       { shift1left_loop_lsp(LSDptr,len); }
62                     else
63                       { shiftleft_loop_lsp(LSDptr,len,i,0); }
64                   }
65                 return DS_to_I(MSDptr,len+k);
66                }
67         } else {
68                 // y<0
69                 var uintL y_ = (uintL)(-y); // Wert von -y, >0
70                 var uintL i = y_%intDsize; // i = (-y) mod intDsize, >=0, <intDsize
71                 var uintL k = floor(y_,intDsize); // k = (-y) div intDsize, >=0
72                 // DS zu x bilden:
73                 var uintD* MSDptr;
74                 var uintC len;
75                 I_to_NDS(x, MSDptr=,len=,); // DS zu x bilden.
76                 if (k>=len) goto sign; // -y >= intDsize*len -> Vorzeichen von x zurück
77                 len -= k; // rechte k Digits einfach streichen
78                 // Noch ist len>0. Um i Bits nach rechts schieben:
79                 if (!(i==0)) // Bei i>0:
80                   { // Schiebe len Digits ab MSDptr um i Bits nach rechts:
81                     if (i==1)
82                       { shift1right_loop_msp(MSDptr,len,sign_of_sintD(mspref(MSDptr,0))); }
83                       else
84                       { shiftrightsigned_loop_msp(MSDptr,len,i); }
85                   }
86                 return DS_to_I(MSDptr,len);
87         }
88 sign:   // Ergebnis ist 0, falls x>=0, und -1, falls x<0:
89         return (minusp(x) ? cl_I(-1) : cl_I(0));
90 }
91
92 }  // namespace cln