]> www.ginac.de Git - cln.git/blob - src/float/lfloat/elem/cl_LF_from_RA.cc
Initial revision
[cln.git] / src / float / lfloat / elem / cl_LF_from_RA.cc
1 // cl_RA_to_LF().
2
3 // General includes.
4 #include "cl_sysdep.h"
5
6 // Specification.
7 #include "cl_LF.h"
8
9
10 // Implementation.
11
12 #include "cl_LF_impl.h"
13 #include "cl_RA.h"
14 #include "cl_integer.h"
15 #include "cl_I.h"
16 #include "cl_F.h"
17
18 const cl_LF cl_RA_to_LF (const cl_RA& x, uintC len)
19 {
20 // Methode:
21 // x ganz -> klar.
22 // x = +/- a/b mit Integers a,b>0:
23 //   Sei k,m so gewählt, daß
24 //     2^(k-1) <= a < 2^k, 2^(m-1) <= b < 2^m.
25 //   Dann ist 2^(k-m-1) < a/b < 2^(k-m+1).
26 //   Ergebnis-Vorzeichen := Vorzeichen von x.
27 //   Berechne k=(integer-length a) und m=(integer-length b).
28 //   Ergebnis-Exponent := k-m.
29 //   Ergebnis-Mantisse:
30 //     Berechne floor(2^(-k+m+16n+1)*a/b) :
31 //       Bei k-m>=16n+1 dividiere a durch (ash b (k-m-16n-1)),
32 //       bei k-m<16n+1 dividiere (ash a (-k+m+16n+1)) durch b.
33 //     Der erste Wert ist >=2^16n, <2^(16n+2).
34 //     Falls er >=2^(16n+1) ist, erhöhe Exponent um 1,
35 //       runde 2 Bits weg und schiebe dabei um 2 Bits nach rechts;
36 //     falls er <2^(16n+1) ist,
37 //       runde 1 Bit weg und schiebe dabei um 1 Bit nach rechts.
38 // NB: Wenn a und b länger sind als len, ist dieser Algorithmus weniger
39 //     effizient, als cl_float(a,len)/cl_float(b,len) zu berechnen. Aber
40 //     es ist wichtig, dass cl_RA_to_LF nicht mehr als 0.5 ulp Fehler hat,
41 //     deswegen belassen wir es beim ineffizienten aber exakten Algorithmus.
42 //     Wenn es auf Rundungsfehler nicht ankommt, muss der Aufrufer im Fall
43 //           ceiling(integer_length(a),intDsize) >= len
44 //        && ceiling(integer_length(b),intDsize) >= len
45 //     einen anderen Algorithmus wählen.
46       if (integerp(x)) {
47         DeclareType(cl_I,x);
48         return cl_I_to_LF(x,len);
49       }
50  {    // x Ratio
51       DeclareType(cl_RT,x);
52       var cl_I a = numerator(x); // +/- a
53       var const cl_I& b = denominator(x); // b
54       var cl_signean sign = -(cl_signean)minusp(a); // Vorzeichen
55       if (!(sign==0)) { a = -a; } // Betrag nehmen, liefert a
56       var sintL lendiff = (sintL)integer_length(a) // (integer-length a)
57                           - (sintL)integer_length(b); // (integer-length b)
58       // |lendiff| < intDsize*2^intCsize. Da für LF-Exponenten ein sintL zur
59       // Verfügung steht, braucht man keinen Test auf Overflow oder Underflow.
60       var uintL difflimit = intDsize*(uintL)len + 1; // 16n+1
61       var cl_I zaehler;
62       var cl_I nenner;
63       if (lendiff > (sintL)difflimit)
64         // 0 <= k-m-16n-1 < k < intDsize*2^intCsize
65         { nenner = ash(b,(uintL)(lendiff - difflimit));
66           zaehler = a;
67         }
68         else
69         // 0 < -k+m+16n+1 <= m+1 + 16n < intDsize*2^intCsize + intDsize*2^intCsize
70         { zaehler = ash(a,(uintL)(difflimit - lendiff)); // (ash a -k+m+16n+1)
71           nenner = b; // b
72         }
73       // Division zaehler/nenner durchführen:
74       var cl_I_div_t q_r = cl_divide(zaehler,nenner);
75       var cl_I& q = q_r.quotient;
76       var cl_I& r = q_r.remainder;
77       // 2^16n <= q < 2^(16n+2), also ist q Bignum mit n+1 Digits.
78       var Lfloat y = allocate_lfloat(len,lendiff+LF_exp_mid,sign); // neues Long-Float
79       var uintD* y_mantMSDptr = arrayMSDptr(TheLfloat(y)->data,len);
80       {var uintD* q_MSDptr = arrayMSDptr(TheBignum(q)->data,len+1);
81        if (mspref(q_MSDptr,0) == 1) // erstes Digit =1 oder =2,3 ?
82          // 2^16n <= q < 2^(16n+1), also 2^(k-m-1) < a/b < 2^(k-m).
83          { // Mantisse mit einer Schiebeschleife um 1 Bit nach rechts füllen:
84            var uintD rounding_bit =
85              shiftrightcopy_loop_msp(q_MSDptr mspop 1,y_mantMSDptr,len,1,1);
86            if ( (rounding_bit == 0) // herausgeschobenes Bit =0 -> abrunden
87                 || ( eq(r,0) // =1 und Rest r > 0 -> aufrunden
88                      // round-to-even
89                      && ((mspref(y_mantMSDptr,len-1) & bit(0)) ==0)
90               )    )
91              goto ab; // abrunden
92              else
93              goto auf; // aufrunden
94          }
95          else
96          // 2^(16n+1) <= q < 2^(16n+2), also 2^(k-m) < a/b < 2^(k-m+1).
97          { // Mantisse mit einer Schiebeschleife um 2 Bit nach rechts füllen:
98            var uintD rounding_bits =
99              shiftrightcopy_loop_msp(q_MSDptr mspop 1,y_mantMSDptr,len,2,mspref(q_MSDptr,0));
100            (TheLfloat(y)->expo)++; // Exponenten incrementieren auf k-m+1
101            if ( ((sintD)rounding_bits >= 0) // herausgeschobenes Bit =0 -> abrunden
102                 || ( ((rounding_bits & bit(intDsize-2)) ==0) // =1 und nächstes Bit =1 oder Rest r > 0 -> aufrunden
103                      && eq(r,0)
104                      // round-to-even
105                      && ((mspref(y_mantMSDptr,len-1) & bit(0)) ==0)
106               )    )
107              goto ab; // abrunden
108              else
109              goto auf; // aufrunden
110          }
111       }
112       auf: // aufrunden
113         { if ( inc_loop_lsp(y_mantMSDptr mspop len,len) )
114             // Übertrag durchs Aufrunden
115             { mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
116               (TheLfloat(y)->expo)++; // Exponenten incrementieren
117         }   }
118       ab: // abrunden
119       return y;
120 }}
121
122 // Timings on an i486 33 MHz, running Linux, in 0.01 sec.
123 // First timing:  cl_I_to_LF(numerator,len)/cl_I_to_LF(denominator,len)
124 // Second timing: cl_RA_to_LF(x,len)
125 // with len = 100.
126 //     num_length    50          70          100         200         500
127 // den_length
128 //
129 //         50     1.86 0.97   1.84 0.97   1.85 0.96   1.86 1.86   1.85 7.14
130 //
131 //         70     1.86 1.33   1.85 1.31   1.85 1.32   1.84 1.84   1.85 7.13
132 //
133 //        100     1.85 1.85   1.86 1.85   1.85 1.84   1.84 1.84   1.86 7.13
134 //
135 //        200     1.85 3.61   1.84 3.61   1.85 3.59   1.85 3.59   1.87 7.12
136 //
137 //        500     1.84 7.44   1.84 7.55   1.85 7.56   1.84 7.66   1.86 7.63
138 //
139 // We see that cl_RA_to_LF is faster only if
140 //            num_length < 2*len && den_length < len
141 // whereas cl_I_to_LF(numerator,len)/cl_I_to_LF(denominator,len) is faster if
142 //            num_length > 2*len || den_length > len