]> www.ginac.de Git - cln.git/blob - src/integer/elem/cl_I_minus.cc
* All Files have been modified for inclusion of namespace cln;
[cln.git] / src / integer / elem / cl_I_minus.cc
1 // binary operator -
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
15 namespace cln {
16
17 const cl_I operator- (const cl_I& x, const cl_I& y)
18 {
19     // Methode:
20     // x Fixnum ->
21     //   y Fixnum -> beide direkt subtrahieren, mit L_to_I beenden
22     //   y Bignum -> falls x=0, (- y); sonst beide zu DS machen, subtrahieren.
23     // x Bignum ->
24     //   y Fixnum -> falls y=0, x; sonst beide zu DS machen, subtrahieren.
25     //   y Bignum -> beide zu DS machen, subtrahieren.
26       var uintD* MSDptr;
27       var uintC len;
28       var uintD* LSDptr;
29       // MSDptr/len/LSDptr bilden die DS des Ergebnisses.
30       if (fixnump(x))
31         { // x ist Fixnum
32           if (fixnump(y))
33             { // x,y sind Fixnums
34               #if (cl_value_len < intLsize)
35               return L_to_I( FN_to_L(x) - FN_to_L(y) ); // als 32-Bit-Zahlen subtrahieren
36               #elif (cl_word_size==64)
37               return Q_to_I( FN_to_Q(x) - FN_to_Q(y) ); // als 64-Bit-Zahlen subtrahieren
38               #else // (cl_value_len == intLsize)
39               var sint32 xhi = sign_of(FN_to_L(x));
40               var uint32 xlo = FN_to_L(x);
41               var sint32 yhi = sign_of(FN_to_L(y));
42               var uint32 ylo = FN_to_L(y);
43               xhi -= yhi;
44               if (xlo < ylo) { xhi -= 1; }
45               xlo -= ylo;
46               return L2_to_I(xhi,xlo);
47               #endif
48             }
49             else
50             { // x ist Fixnum, y ist Bignum, also y länger
51               #if (intDsize==64)
52               var sint64 x_ = FN_to_L(x); // Wert von x
53               #else
54               var sint32 x_ = FN_to_L(x); // Wert von x
55               #endif
56               if (FN_L_zerop(x,x_)) { return -y; } // bei x=0 Ergebnis (- y)
57               CL_ALLOCA_STACK;
58               BN_to_NDS_1(y, MSDptr=,len=,LSDptr=); // NDS zu y bilden.
59               // vorsorglich 1 Digit mehr belegen:
60               { var sintD sign = sign_of_sintD(mspref(MSDptr,0));
61                 lsprefnext(MSDptr) = sign; len++;
62               }
63               // Negierschleife:
64               neg_loop_lsp(LSDptr,len);
65               // MSDigit ist nun = 0x0000 oder = 0xFFFF
66               // x_ zu den oberen pFN_maxlength Digits von -y addieren:
67               {
68                 #if (intDsize==64)
69                 var uint64 y_ = lspref(LSDptr,0);
70                 var uint64 y_new = y_+(uint64)x_;
71                 lspref(LSDptr,0) = y_new;
72                 #else
73                 var uint32 y_ = pFN_maxlength_digits_at(LSDptr);
74                 var uint32 y_new = y_+(uint32)x_;
75                 set_pFN_maxlength_digits_at(LSDptr,y_new);
76                 #endif
77                 var uintD* midptr = LSDptr lspop pFN_maxlength;
78                 if (y_new < y_)
79                   { // Carry.
80                     if (!FN_L_minusp(x,x_)) // kürzerer Summand war positiv
81                       // Dann ist ein positiver Übertrag weiterzutragen
82                       // (Beispiel: 0002FFFC + 0007 = 00030003)
83                       { DS_1_plus(midptr,len-pFN_maxlength); }
84                   }
85                   else
86                   { // Kein Carry.
87                     if (FN_L_minusp(x,x_)) // kürzerer Summand war negativ
88                       // Dann ist ein negativer Übertrag weiterzutragen
89                       // (Beispiel: 00020003 + FFF5 = 0001FFF8)
90                       { DS_minus1_plus(midptr,len-pFN_maxlength); }
91               }   }
92               return DS_to_I(MSDptr,len); // DS wieder zum Integer machen
93             }
94         }
95         else
96         { // x ist Bignum
97           if (fixnump(y))
98             { // x ist Bignum, y ist Fixnum, also x länger
99               #if (intDsize==64)
100               var sint64 y_ = FN_to_L(y); // Wert von y
101               #else
102               var sint32 y_ = FN_to_L(y); // Wert von y
103               #endif
104               if (FN_L_zerop(y,y_)) { return x; } // bei y=0 Ergebnis x
105               CL_ALLOCA_STACK;
106               BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); // NDS zu x bilden.
107               // len>=bn_minlength. len>pFN_maxlength erzwingen:
108               if ((bn_minlength==pFN_maxlength) && (len==pFN_maxlength))
109                 { var sintD sign = sign_of_sintD(mspref(MSDptr,0));
110                   lsprefnext(MSDptr) = sign; len++;
111                 }
112               // y_ von den oberen pFN_maxlength Digits von x subtrahieren:
113               {
114                 #if (intDsize==64)
115                 var uint64 x_ = lspref(LSDptr,0);
116                 var uint64 x_new = x_-(uint64)y_;
117                 lspref(LSDptr,0) = x_new;
118                 #else
119                 var uint32 x_ = pFN_maxlength_digits_at(LSDptr);
120                 var uint32 x_new = x_-(uint32)y_;
121                 set_pFN_maxlength_digits_at(LSDptr,x_new);
122                 #endif
123                 var uintD* midptr = LSDptr lspop pFN_maxlength;
124                 if (x_new > x_)
125                   { // Carry.
126                     if (!FN_L_minusp(y,y_)) // kürzerer Summand war positiv
127                       // Dann ist ein negativer Übertrag weiterzutragen
128                       // (Beispiel: 00030003 - 0007 = 0002FFFC)
129                       { DS_minus1_plus(midptr,len-pFN_maxlength); }
130                   }
131                   else
132                   { // Kein Carry.
133                     if (FN_L_minusp(y,y_)) // kürzerer Summand war negativ
134                       // Dann ist ein positiver Übertrag weiterzutragen
135                       // (Beispiel: 0002FFF8 - FFF5 = 00030003)
136                       { DS_1_plus(midptr,len-pFN_maxlength); }
137               }   }
138               return DS_to_I(MSDptr,len); // DS wieder zum Integer machen
139             }
140             else
141             { // x und y sind Bignums
142               if (TheBignum(x)->length > TheBignum(y)->length)
143                 { // x das längere von beiden.
144                   CL_ALLOCA_STACK;
145                   BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); // NDS zu x bilden.
146                   var const uintD* yMSDptr;
147                   var uintC ylen;
148                   var const uintD* yLSDptr;
149                   BN_to_NDS_nocopy(y, yMSDptr=,ylen=,yLSDptr=); // NDS zu y bilden.
150                   // yMSDptr/ylen/yLSDptr bilden die DS des kürzeren Arguments y.
151                   // Es ist len>ylen.
152                   // subtrahieren:
153                   { var uintD* midptr = LSDptr lspop ylen;
154                     var uintD carry = subfrom_loop_lsp(yLSDptr,LSDptr,ylen);
155                     if (carry)
156                       { // Carry.
157                         if ((sintD)mspref(yMSDptr,0) >=0) // kürzerer Summand war positiv
158                           // Dann ist ein negativer Übertrag weiterzutragen
159                           // (Beispiel: 00030003 - 0007 = 0002FFFC)
160                           { DS_minus1_plus(midptr,len-ylen); }
161                       }
162                       else
163                       { // Kein Carry.
164                         if ((sintD)mspref(yMSDptr,0) <0) // kürzerer Summand war negativ
165                           // Dann ist ein positiver Übertrag weiterzutragen
166                           // (Beispiel: 0002FFF8 - FFF5 = 00030003)
167                           { DS_1_plus(midptr,len-ylen); }
168                   }   }
169                   return DS_to_I(MSDptr,len); // DS wieder zum Integer machen
170                 }
171                 else
172                 { // y das längere von beiden.
173                   CL_ALLOCA_STACK;
174                   BN_to_NDS_1(y, MSDptr=,len=,LSDptr=); // NDS zu y bilden.
175                   // vorsorglich 1 Digit mehr belegen:
176                   { var sintD sign = sign_of_sintD(mspref(MSDptr,0));
177                     lsprefnext(MSDptr) = sign; len++;
178                   }
179                   // Negierschleife:
180                   neg_loop_lsp(LSDptr,len);
181                   // MSDigit ist nun = 0x0000 oder = 0xFFFF
182                   var const uintD* xMSDptr;
183                   var uintC xlen;
184                   var const uintD* xLSDptr;
185                   BN_to_NDS_nocopy(x, xMSDptr=,xlen=,xLSDptr=); // NDS zu x bilden.
186                   // xMSDptr/xlen/xLSDptr bilden die DS des kürzeren Arguments x.
187                   // Es ist jetzt len>xlen.
188                   // addieren:
189                   { var uintD* midptr = LSDptr lspop xlen;
190                     var uintD carry = addto_loop_lsp(xLSDptr,LSDptr,xlen);
191                     if (carry)
192                       { // Carry.
193                         if ((sintD)mspref(xMSDptr,0) >=0) // kürzerer Summand war positiv
194                           // Dann ist ein positiver Übertrag weiterzutragen
195                           // (Beispiel: 0002FFFC + 0007 = 00030003)
196                           { DS_1_plus(midptr,len-xlen); }
197                       }
198                       else
199                       { // Kein Carry.
200                         if ((sintD)mspref(xMSDptr,0) <0) // kürzerer Summand war negativ
201                           // Dann ist ein negativer Übertrag weiterzutragen
202                           // (Beispiel: 00020003 + FFF5 = 0001FFF8)
203                           { DS_minus1_plus(midptr,len-xlen); }
204                   }   }
205                   return DS_to_I(MSDptr,len); // DS wieder zum Integer machen
206                 }
207         }   }
208 }
209
210 }  // namespace cln