# Addition/Subtraktion von Integers # Macro: In der DS MSDptr/len/LSDptr wird eine 1 unterhalb des Pointers ptr # addiert. Unterhalb von MSDptr muss 1 Digit Platz sein. # Dabei ist ptr - MSDptr = count und 0 < count <= len . # Eventuell wird MSDptr erniedrigt und len erhöht. #define DS_1_plus(ptr,count) \ { \ var uintD* ptr_from_DS_1_plus = (ptr); \ var uintC count_from_DS_1_plus = (count); \ while (1) { \ if (--count_from_DS_1_plus==0) { # Zähler erniedrigen \ # Beim Most Significant Digit angelangt \ *(--ptr_from_DS_1_plus) += 1; \ # jetzt ist ptr_from_DS_1_plus = MSDptr \ if (*ptr_from_DS_1_plus == bit(intDsize-1)) { \ # 7FFF + 1 muss zu 00008000 werden: \ *--MSDptr = 0; \ len++; \ if (uintWCoverflow(len)) { \ RESTORE_NUM_STACK; BN_ueberlauf(); \ } \ } \ break; \ } \ if (!((*(--ptr_from_DS_1_plus) += 1) == 0)) # weiterincrementieren \ break; # kein weiterer Übertrag -> Schleife abbrechen \ } \ } # Macro: In der DS MSDptr/len/LSDptr wird eine 1 unterhalb des Pointers ptr # subtrahiert. Unterhalb von MSDptr muss 1 Digit Platz sein. # Dabei ist ptr - MSDptr = count und 0 < count <= len . # Eventuell wird MSDptr erniedrigt und len erhöht. #define DS_minus1_plus(ptr,count) \ { \ var uintD* ptr_from_DS_minus1_plus = (ptr); \ var uintC count_from_DS_minus1_plus = (count); \ while (1) { \ if (--count_from_DS_minus1_plus==0) { # Zähler erniedrigen \ # Beim Most Significant Digit angelangt \ *(--ptr_from_DS_minus1_plus) -= 1; \ # jetzt ist ptr_from_DS_minus1_plus = MSDptr \ if (*ptr_from_DS_minus1_plus == (uintD)bit(intDsize-1)-1) { \ # 8000 - 1 muss zu FFFF7FFF werden: \ *--MSDptr = (uintD)(-1); \ len++; \ if (uintWCoverflow(len)) { \ RESTORE_NUM_STACK; BN_ueberlauf(); \ } \ } \ break; \ } \ if (!((sintD)(*(--ptr_from_DS_minus1_plus) -= 1) == -1)) # weiterdecrementieren \ break; # kein weiterer Übertrag -> Schleife abbrechen \ } \ } # (1+ x), wo x ein Integer ist. Ergebnis Integer. # can trigger GC modexp maygc object I_1_plus_I (object x) { if (I_fixnump(x)) { # x ist Fixnum if (eq(x,Fixnum_minus1)) return Fixnum_0; # (1+ -1) = 0 if (!eq(x,Fixnum_mpos)) return fixnum_inc(x,1); # bleibt Fixnum: direkt 1 addieren } # die sichere Methode { SAVE_NUM_STACK # num_stack retten var uintD* MSDptr; var uintC len; var uintD* LSDptr; I_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden. DS_1_plus(LSDptr,len); # zur NDS 1 addieren var object result = DS_to_I(MSDptr,len); # wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } # (1- x), wo x ein Integer ist. Ergebnis Integer. # can trigger GC modexp maygc object I_minus1_plus_I (object x) { if (I_fixnump(x)) { # x ist Fixnum if (eq(x,Fixnum_0)) return Fixnum_minus1; # (1- 0) = -1 if (!eq(x,Fixnum_mneg)) return fixnum_inc(x,-1); # bleibt Fixnum: direkt 1 subtrahieren } # die sichere Methode { SAVE_NUM_STACK # num_stack retten var uintD* MSDptr; var uintC len; var uintD* LSDptr; I_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden. DS_minus1_plus(LSDptr,len); # von der NDS 1 subtrahieren var object result = DS_to_I(MSDptr,len); # wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } # (+ x y), wo x und y Integers sind. Ergebnis Integer. # can trigger GC modexp maygc object I_I_plus_I (object x, object y) { # Methode: # x Fixnum -> # y Fixnum -> beide direkt addieren, mit L_to_I beenden # y Bignum -> falls x=0, y; sonst beide zu DS machen, addieren. # x Bignum -> # y Fixnum -> falls y=0, x; sonst beide zu DS machen, addieren. # y Bignum -> beide zu DS machen, addieren. var uintD* MSDptr; var uintC len; var uintD* LSDptr; # MSDptr/len/LSDptr bilden die DS des Ergebnisses. if (I_fixnump(x)) { # x ist Fixnum if (I_fixnump(y)) { # x,y sind Fixnums #if (oint_data_len+1 < intVsize) return V_to_I( FN_to_V(x) + FN_to_V(y) ); # als intVsize-Bit-Zahlen addieren #elif defined(intQsize) return Q_to_I( FN_to_Q(x) + FN_to_Q(y) ); # als 64-Bit-Zahlen addieren #elif (intVsize==32) var sint32 xhi = FN_sign(x); var uint32 xlo = FN_to_V(x); var sint32 yhi = FN_sign(y); var uint32 ylo = FN_to_V(y); xhi += yhi; xlo += ylo; if (xlo < ylo) xhi += 1; return L2_to_I(xhi,xlo); #endif } else { # x ist Fixnum, y ist Bignum var object h; h = x; x = y; y = h; # x und y vertauschen goto xBN_yFN; } } else { # x ist Bignum if (I_fixnump(y)) xBN_yFN: { # x ist Bignum, y ist Fixnum, also x länger var sintV y_ = FN_to_V(y); # Wert von y if (FN_V_zerop(y,y_)) return x; # bei y=0 Ergebnis x { SAVE_NUM_STACK # num_stack retten BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden. # len>=bn_minlength. len>pFN_maxlength erzwingen: if ((bn_minlength==pFN_maxlength) && (len==pFN_maxlength)) { var sintD sign = sign_of_sintD(MSDptr[0]); *--MSDptr = sign; len++; } # y_ zu den oberen pFN_maxlength Digits von x addieren: { var uintD* midptr = &LSDptr[-(uintP)pFN_maxlength]; var uintV x_ = pFN_maxlength_digits_at(midptr); var uintV x_new = x_+(uintV)y_; set_pFN_maxlength_digits_at(midptr,x_new); if (x_new < x_) { # Carry. if (!FN_V_minusp(y,y_)) { # kürzerer Summand war positiv # Dann ist ein positiver Übertrag weiterzutragen # (Beispiel: 0002FFFC + 0007 = 00030003) DS_1_plus(midptr,len-pFN_maxlength); } } else { # Kein Carry. if (FN_V_minusp(y,y_)) { # kürzerer Summand war negativ # Dann ist ein negativer Übertrag weiterzutragen # (Beispiel: 00020003 + FFF5 = 0001FFF8) DS_minus1_plus(midptr,len-pFN_maxlength); } } } var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } else { # x und y sind Bignums SAVE_NUM_STACK # num_stack retten if (Bignum_length(x) < Bignum_length(y)) { var object h; h = x; x = y; y = h; # x und y vertauschen } # Nun ist x das längere von beiden. BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden. var uintD* yMSDptr; var uintC ylen; var uintD* yLSDptr; BN_to_NDS_nocopy(y, yMSDptr=,ylen=,yLSDptr=); # NDS zu y bilden. # yMSDptr/ylen/yLSDptr bilden die DS des kürzeren Arguments y. # len>ylen erzwingen: if (len==ylen) { var sintD sign = sign_of_sintD(MSDptr[0]); *--MSDptr = sign; len++; if (uintWCoverflow(len)) { RESTORE_NUM_STACK; BN_ueberlauf(); } } # addieren: { var uintD* midptr = LSDptr-(uintP)ylen; var uintD carry = addto_loop_down(yLSDptr,LSDptr,ylen); if (carry) { # Carry. if ((sintD)yMSDptr[0] >=0) { # kürzerer Summand war positiv # Dann ist ein positiver Übertrag weiterzutragen # (Beispiel: 0002FFFC + 0007 = 00030003) DS_1_plus(midptr,len-ylen); } } else { # Kein Carry. if ((sintD)yMSDptr[0] <0) { # kürzerer Summand war negativ # Dann ist ein negativer Übertrag weiterzutragen # (Beispiel: 00020003 + FFF5 = 0001FFF8) DS_minus1_plus(midptr,len-ylen); } } } var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } } # (- x), wenn x ein Integer ist. Ergebnis Integer. # can trigger GC local maygc object I_minus_I (object x) { if (I_fixnump(x)) { # Fixnum -> Long, negieren, -> Integer #if (oint_data_len+1 < intVsize) return V_to_I(- FN_to_V(x)); #elif defined(intQsize) return Q_to_I(- FN_to_Q(x)); #elif (intVsize==32) var sint32 xhi = FN_sign(x); var uint32 xlo = FN_to_V(x); if (xlo==0) { xhi = -xhi; } else { xlo = -xlo; xhi = ~xhi; } return L2_to_I(xhi,xlo); #endif } else { # x Bignum SAVE_NUM_STACK # num_stack retten var uintD* MSDptr; var uintC len; var uintD* LSDptr; BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden, len>0 # vorsorglich 1 Digit mehr belegen: { var sintD sign = sign_of_sintD(MSDptr[0]); *--MSDptr = sign; len++; if (uintWCoverflow(len)) { RESTORE_NUM_STACK; BN_ueberlauf(); } } # Negierschleife: neg_loop_down(LSDptr,len); # MSDigit ist nun = 0x0000 oder = 0xFFFF var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } # (- x y), wo x und y Integers sind. Ergebnis Integer. # can trigger GC modexp maygc object I_I_minus_I (object x, object y) { # Methode: # x Fixnum -> # y Fixnum -> beide direkt subtrahieren, mit L_to_I beenden # y Bignum -> falls x=0, (- y); sonst beide zu DS machen, subtrahieren. # x Bignum -> # y Fixnum -> falls y=0, x; sonst beide zu DS machen, subtrahieren. # y Bignum -> beide zu DS machen, subtrahieren. var uintD* MSDptr; var uintC len; var uintD* LSDptr; # MSDptr/len/LSDptr bilden die DS des Ergebnisses. if (I_fixnump(x)) { # x ist Fixnum if (I_fixnump(y)) { # x,y sind Fixnums #if (oint_data_len+1 < intVsize) return V_to_I( FN_to_V(x) - FN_to_V(y) ); # als intVsize-Bit-Zahlen subtrahieren #elif defined(intQsize) return Q_to_I( FN_to_Q(x) - FN_to_Q(y) ); # als 64-Bit-Zahlen subtrahieren #elif (intVsize==32) var sint32 xhi = FN_sign(x); var uint32 xlo = FN_to_V(x); var sint32 yhi = FN_sign(y); var uint32 ylo = FN_to_V(y); xhi -= yhi; if (xlo < ylo) xhi -= 1; xlo -= ylo; return L2_to_I(xhi,xlo); #endif } else { # x ist Fixnum, y ist Bignum, also y länger var sintV x_ = FN_to_V(x); # Wert von x if (FN_V_zerop(x,x_)) return I_minus_I(y); # bei x=0 Ergebnis (- y) { SAVE_NUM_STACK # num_stack retten BN_to_NDS_1(y, MSDptr=,len=,LSDptr=); # NDS zu y bilden. # vorsorglich 1 Digit mehr belegen: { var sintD sign = sign_of_sintD(MSDptr[0]); *--MSDptr = sign; len++; if (uintWCoverflow(len)) { RESTORE_NUM_STACK; BN_ueberlauf(); } } # Negierschleife: neg_loop_down(LSDptr,len); # MSDigit ist nun = 0x0000 oder = 0xFFFF # x_ zu den oberen pFN_maxlength Digits von -y addieren: { var uintD* midptr = &LSDptr[-(uintP)pFN_maxlength]; var uintV y_ = pFN_maxlength_digits_at(midptr); var uintV y_new = y_+(uintV)x_; set_pFN_maxlength_digits_at(midptr,y_new); if (y_new < y_) { # Carry. if (!FN_V_minusp(x,x_)) { # kürzerer Summand war positiv # Dann ist ein positiver Übertrag weiterzutragen # (Beispiel: 0002FFFC + 0007 = 00030003) DS_1_plus(midptr,len-pFN_maxlength); } } else { # Kein Carry. if (FN_V_minusp(x,x_)) { # kürzerer Summand war negativ # Dann ist ein negativer Übertrag weiterzutragen # (Beispiel: 00020003 + FFF5 = 0001FFF8) DS_minus1_plus(midptr,len-pFN_maxlength); } } } var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } } else { # x ist Bignum if (I_fixnump(y)) { # x ist Bignum, y ist Fixnum, also x länger var sintV y_ = FN_to_V(y); # Wert von y if (FN_V_zerop(y,y_)) return x; # bei y=0 Ergebnis x { SAVE_NUM_STACK # num_stack retten BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden. # len>=bn_minlength. len>pFN_maxlength erzwingen: if ((bn_minlength==pFN_maxlength) && (len==pFN_maxlength)) { var sintD sign = sign_of_sintD(MSDptr[0]); *--MSDptr = sign; len++; } # y_ von den oberen pFN_maxlength Digits von x subtrahieren: { var uintD* midptr = &LSDptr[-(uintP)pFN_maxlength]; var uintV x_ = pFN_maxlength_digits_at(midptr); var uintV x_new = x_-(uintV)y_; set_pFN_maxlength_digits_at(midptr,x_new); if (x_new > x_) { # bzw. (x_ < (uintV)y_), da y_>0 # Carry. if (!FN_V_minusp(y,y_)) { # kürzerer Summand war positiv # Dann ist ein negativer Übertrag weiterzutragen # (Beispiel: 00030003 - 0007 = 0002FFFC) DS_minus1_plus(midptr,len-pFN_maxlength); } } else { # Kein Carry. if (FN_V_minusp(y,y_)) { # kürzerer Summand war negativ # Dann ist ein positiver Übertrag weiterzutragen # (Beispiel: 0002FFF8 - FFF5 = 00030003) DS_1_plus(midptr,len-pFN_maxlength); } } } var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } else { # x und y sind Bignums if (Bignum_length(x) > Bignum_length(y)) { # x das längere von beiden. SAVE_NUM_STACK # num_stack retten BN_to_NDS_1(x, MSDptr=,len=,LSDptr=); # NDS zu x bilden. var uintD* yMSDptr; var uintC ylen; var uintD* yLSDptr; BN_to_NDS_nocopy(y, yMSDptr=,ylen=,yLSDptr=); # NDS zu y bilden. # yMSDptr/ylen/yLSDptr bilden die DS des kürzeren Arguments y. # Es ist len>ylen. # subtrahieren: { var uintD* midptr = LSDptr-(uintP)ylen; var uintD carry = subfrom_loop_down(yLSDptr,LSDptr,ylen); if (carry) { # Carry. if ((sintD)yMSDptr[0] >=0) { # kürzerer Summand war positiv # Dann ist ein negativer Übertrag weiterzutragen # (Beispiel: 00030003 - 0007 = 0002FFFC) DS_minus1_plus(midptr,len-ylen); } } else { # Kein Carry. if ((sintD)yMSDptr[0] <0) { # kürzerer Summand war negativ # Dann ist ein positiver Übertrag weiterzutragen # (Beispiel: 0002FFF8 - FFF5 = 00030003) DS_1_plus(midptr,len-ylen); } } } var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } else { # y das längere von beiden. SAVE_NUM_STACK # num_stack retten BN_to_NDS_1(y, MSDptr=,len=,LSDptr=); # NDS zu y bilden. # vorsorglich 1 Digit mehr belegen: { var sintD sign = sign_of_sintD(MSDptr[0]); *--MSDptr = sign; len++; if (uintWCoverflow(len)) { RESTORE_NUM_STACK; BN_ueberlauf(); } } # Negierschleife: neg_loop_down(LSDptr,len); # MSDigit ist nun = 0x0000 oder = 0xFFFF var uintD* xMSDptr; var uintC xlen; var uintD* xLSDptr; BN_to_NDS_nocopy(x, xMSDptr=,xlen=,xLSDptr=); # NDS zu x bilden. # xMSDptr/xlen/xLSDptr bilden die DS des kürzeren Arguments x. # Es ist jetzt len>xlen. # addieren: { var uintD* midptr = LSDptr-(uintP)xlen; var uintD carry = addto_loop_down(xLSDptr,LSDptr,xlen); if (carry) { # Carry. if ((sintD)xMSDptr[0] >=0) { # kürzerer Summand war positiv # Dann ist ein positiver Übertrag weiterzutragen # (Beispiel: 0002FFFC + 0007 = 00030003) DS_1_plus(midptr,len-xlen); } } else { # Kein Carry. if ((sintD)xMSDptr[0] <0) { # kürzerer Summand war negativ # Dann ist ein negativer Übertrag weiterzutragen # (Beispiel: 00020003 + FFF5 = 0001FFF8) DS_minus1_plus(midptr,len-xlen); } } } var object result = DS_to_I(MSDptr,len); # DS wieder zum Integer machen RESTORE_NUM_STACK # num_stack zurück return result; } } } } # (abs x), wenn x ein Integer ist. Ergebnis Integer. # can trigger GC local maygc object I_abs_I (object x) { # Methode: # Bei x<0: (- x), sonst x. if (R_minusp(x)) return I_minus_I(x); else return x; }