]> www.ginac.de Git - cln.git/blob - src/float/lfloat/elem/cl_LF_scale_I.cc
Extend the exponent range from 32 bits to 64 bits on selected platforms.
[cln.git] / src / float / lfloat / elem / cl_LF_scale_I.cc
1 // scale_float().
2
3 // General includes.
4 #include "cl_sysdep.h"
5
6 // Specification.
7 #include "cln/lfloat.h"
8
9
10 // Implementation.
11
12 #include "cl_LF.h"
13 #include "cl_LF_impl.h"
14 #include "cl_F.h"
15 #include "cl_I.h"
16
17 namespace cln {
18
19 const cl_LF scale_float (const cl_LF& x, const cl_I& delta)
20 {
21   // Methode:
22   // delta=0 -> x als Ergebnis
23   // x=0.0 -> x als Ergebnis
24   // delta muß ein Integer betragsmäßig <= LF_exp_high-LF_exp_low sein.
25   // Neues LF mit um delta vergrößertem Exponenten bilden.
26       if (eq(delta,0)) { return x; } // delta=0 -> x als Ergebnis
27       var uintE uexp = TheLfloat(x)->expo;
28       if (uexp==0) { return x; }
29       var uintE udelta;
30       // |delta| muß <= LF_exp_high-LF_exp_low < 2^32 sein. Wie bei I_to_UL:
31         if (fixnump(delta)) {
32                 // Fixnum
33                 var sintV sdelta = FN_to_V(delta);
34                 if (sdelta >= 0)
35                         { udelta = sdelta; goto pos; }
36                 else
37                         { udelta = sdelta; goto neg; }
38         } else {
39             // Bignum
40             var cl_heap_bignum* bn = TheBignum(delta);
41             if ((sintD)mspref(arrayMSDptr(bn->data,bn->length),0) >= 0) {
42                 #define IF_LENGTH(i)  \
43                   if (bn_minlength <= i) /* genau i Digits überhaupt möglich? */\
44                     if (bn->length == i) /* genau i Digits? */                  \
45                       /* 2^((i-1)*intDsize-1) <= delta < 2^(i*intDsize-1) */    \
46                       if ( (i*intDsize-1 > 32)                                  \
47                            && ( ((i-1)*intDsize-1 >= 32)                        \
48                                 || (mspref(arrayMSDptr(bn->data,i),0) >= (uintD)bitc(32-(i-1)*intDsize)) \
49                          )    )                                                 \
50                         goto overflow;                                          \
51                         else
52                 IF_LENGTH(1)
53                         { udelta = get_uint1D_Dptr(arrayLSDptr(bn->data,1)); goto pos; }
54                 IF_LENGTH(2)
55                         { udelta = get_uint2D_Dptr(arrayLSDptr(bn->data,2)); goto pos; }
56                 IF_LENGTH(3)
57                         { udelta = get_uint3D_Dptr(arrayLSDptr(bn->data,3)); goto pos; }
58                 IF_LENGTH(4)
59                         { udelta = get_uint4D_Dptr(arrayLSDptr(bn->data,4)); goto pos; }
60                 IF_LENGTH(5)
61                         { udelta = get_uint4D_Dptr(arrayLSDptr(bn->data,5)); goto pos; }
62                 #undef IF_LENGTH
63                 goto overflow; // delta zu groß
64             } else {
65                 #define IF_LENGTH(i)  \
66                   if (bn_minlength <= i) /* genau i Digits überhaupt möglich? */\
67                     if (bn->length == i) /* genau i Digits? */                  \
68                       /* - 2^((i-1)*intDsize-1) > delta >= - 2^(i*intDsize-1) */\
69                       if ( (i*intDsize-1 > 32)                                  \
70                            && ( ((i-1)*intDsize-1 >= 32)                        \
71                                 || (mspref(arrayMSDptr(bn->data,i),0) < (uintD)(-bitc(32-(i-1)*intDsize))) \
72                          )    )                                                 \
73                         goto underflow;                                         \
74                         else
75                 IF_LENGTH(1)
76                         { udelta = get_sint1D_Dptr(arrayLSDptr(bn->data,1)); goto pos; }
77                 IF_LENGTH(2)
78                         { udelta = get_sint2D_Dptr(arrayLSDptr(bn->data,2)); goto pos; }
79                 IF_LENGTH(3)
80                         { udelta = get_sint3D_Dptr(arrayLSDptr(bn->data,3)); goto pos; }
81                 IF_LENGTH(4)
82                         { udelta = get_sint4D_Dptr(arrayLSDptr(bn->data,4)); goto pos; }
83                 IF_LENGTH(5)
84                         { udelta = get_sint4D_Dptr(arrayLSDptr(bn->data,5)); goto pos; }
85                 #undef IF_LENGTH
86                 goto underflow; // delta zu klein
87             }
88         }
89
90       pos: // udelta = delta >=0
91         if (   ((uexp = uexp+udelta) < udelta) // Exponent-Überlauf?
92             || (uexp > LF_exp_high) // oder Exponent zu groß?
93            )
94           overflow:
95           { cl_error_floating_point_overflow(); }
96         goto ok;
97
98       neg: // delta <0, udelta = 2^32+delta
99         if (   ((uexp = uexp+udelta) >= udelta) // oder Exponent-Unterlauf?
100             || (uexp < LF_exp_low) // oder Exponent zu klein?
101            )
102           underflow:
103           { cl_error_floating_point_underflow(); }
104         goto ok;
105
106       ok:
107         var uintC len = TheLfloat(x)->len;
108         return encode_LFu(TheLfloat(x)->sign,uexp,arrayMSDptr(TheLfloat(x)->data,len),len);
109 }
110
111 }  // namespace cln