]> www.ginac.de Git - cln.git/blob - src/float/lfloat/elem/cl_LF_from_I.cc
Initial revision
[cln.git] / src / float / lfloat / elem / cl_LF_from_I.cc
1 // cl_I_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_integer.h"
14 #include "cl_I.h"
15 #include "cl_DS.h"
16 #include "cl_F.h"
17
18 const cl_LF cl_I_to_LF (const cl_I& x, uintC len)
19 {
20 // Methode:
21 // x=0 -> Ergebnis 0.0
22 // Merke Vorzeichen von x.
23 // x:=(abs x)
24 // Exponent:=(integer-length x)
25 // Mantisse enthalte die höchstwertigen 16n Bits des Integers x (wobei die
26 //   führenden 16-(e mod 16) Nullbits zu streichen sind).
27 // Runde die weiteren Bits weg:
28 //   Kommen keine mehr -> abrunden,
29 //   nächstes Bit = 0 -> abrunden,
30 //   nächstes Bit = 1 und Rest =0 -> round-to-even,
31 //   nächstes Bit = 1 und Rest >0 -> aufrunden.
32 // Bei Aufrundung: rounding overflow -> Mantisse um 1 Bit nach rechts schieben
33 //   und Exponent incrementieren.
34       if (eq(x,0)) { return encode_LF0(len); } // x=0 -> Ergebnis 0.0
35       var cl_signean sign = -(cl_signean)minusp(x); // Vorzeichen von x
36       var cl_I abs_x = (sign==0 ? x : -x);
37       var uintL exp = integer_length(abs_x); // (integer-length x) < intDsize*2^intCsize
38       // Teste, ob exp <= LF_exp_high-LF_exp_mid :
39       if (   (log2_intDsize+intCsize < 32)
40           && ((uintL)(intDsize*bitc(intCsize)-1) <= (uintL)(LF_exp_high-LF_exp_mid))
41          )
42         {} // garantiert exp <= intDsize*2^intCsize-1 <= LF_exp_high-LF_exp_mid
43         else
44         { if (!(exp <= (uintL)(LF_exp_high-LF_exp_mid))) { cl_error_floating_point_overflow(); } }
45       // Long-Float bauen:
46       var Lfloat y = allocate_lfloat(len,exp+LF_exp_mid,sign);
47       var uintD* y_mantMSDptr = arrayMSDptr(TheLfloat(y)->data,len);
48       var const uintD* x_MSDptr;
49       var uintC x_len;
50       I_to_NDS_nocopy(abs_x, x_MSDptr=,x_len=,,cl_false,); // NDS zu x bilden, x_len>0
51       // x_MSDptr/x_len/.. um (exp mod 16) Bits nach rechts shiften und in
52       // y einfüllen (genauer: nur maximal len Digits davon):
53       {var uintL shiftcount = exp % intDsize;
54        // Die NDS fängt mit intDsize-shiftcount Nullbits an, dann kommt eine 1.
55        if (x_len > len)
56          { x_len -= 1+len;
57            if (shiftcount>0)
58              { var uintD carry_rechts =
59                  shiftrightcopy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,len,shiftcount,mspref(x_MSDptr,0));
60                // Mantisse ist gefüllt. Runden:
61                if ( ((sintD)carry_rechts >= 0) // nächstes Bit =0 -> abrunden
62                     || ( ((carry_rechts & ((uintD)bit(intDsize-1)-1)) ==0) // =1, Rest >0 -> aufrunden
63                          && !test_loop_msp(x_MSDptr mspop 1 mspop len,x_len)
64                          // round-to-even
65                          && ((mspref(y_mantMSDptr,len-1) & bit(0)) ==0)
66                   )    )
67                  goto ab; // aufrunden
68                  else
69                  goto auf; // aufrunden
70              }
71              else
72              { copy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,len);
73                // Mantisse ist gefüllt. Runden:
74                var const uintD* ptr = x_MSDptr mspop 1 mspop len;
75                if ( (x_len==0) // keine Bits mehr -> abrunden
76                     || ((sintD)mspref(ptr,0) >= 0) // nächstes Bit =0 -> abrunden
77                     || ( ((mspref(ptr,0) & ((uintD)bit(intDsize-1)-1)) ==0) // =1, Rest >0 -> aufrunden
78                          && !test_loop_msp(ptr mspop 1,x_len-1)
79                          // round-to-even
80                          && ((lspref(ptr,0) & bit(0)) ==0)
81                   )    )
82                  goto ab; // aufrunden
83                  else
84                  goto auf; // aufrunden
85              }
86            auf: // aufrunden
87              if ( inc_loop_lsp(y_mantMSDptr mspop len,len) )
88                // Übertrag durchs Aufrunden
89                { mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
90                  // Exponenten incrementieren:
91                  if (   (log2_intDsize+intCsize < 32)
92                      && ((uintL)(intDsize*bitc(intCsize)-1) < (uintL)(LF_exp_high-LF_exp_mid))
93                     )
94                    // garantiert exp < intDsize*2^intCsize-1 <= LF_exp_high-LF_exp_mid
95                    { (TheLfloat(y)->expo)++; } // jetzt exp <= LF_exp_high-LF_exp_mid
96                    else
97                    { if (++(TheLfloat(y)->expo) == LF_exp_high+1) { cl_error_floating_point_overflow(); } }
98                }
99            ab: // abrunden
100              ;
101          }
102          else // x_len <= len
103          { var uintD carry_rechts;
104            len -= x_len;
105            x_len -= 1;
106            if (shiftcount>0)
107              { carry_rechts = shiftrightcopy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,x_len,shiftcount,mspref(x_MSDptr,0)); }
108              else
109              { copy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,x_len); carry_rechts = 0; }
110           {var uintD* y_ptr = y_mantMSDptr mspop x_len;
111            msprefnext(y_ptr) = carry_rechts; // Carry als nächstes Digit
112            clear_loop_msp(y_ptr,len); // dann len-x_len Nulldigits
113          }}
114       }
115       return y;
116 }