]> www.ginac.de Git - cln.git/blob - src/float/cl_F.h
f11107de33c8bbf305fba1f67cff7c1688e042c0
[cln.git] / src / float / cl_F.h
1 // cl_F internals
2
3 #ifndef _CL_F_H
4 #define _CL_F_H
5
6 #include "cl_number.h"
7 #include "cl_macros.h"
8 #include "cl_float.h"
9
10
11 nonreturning_function(extern, cl_error_floating_point_overflow, (void));
12 nonreturning_function(extern, cl_error_floating_point_underflow, (void));
13
14 #define underflow_allowed()  (! cl_inhibit_floating_point_underflow)
15
16
17 // For all floating-point formats:
18 // Sign s, Exponent e, Mantissa mk-1,...,m0
19 // represents the number (-1)^s * 2^(e-_EXP_MID) * [0 . 1 mk-1 ... m0]
20 // e=0 represents the number 0, always with sign s=0 (and mantissa =0).
21 // _exp_low and _exp_high are (inclusive) bounds for e.
22 // Bits for   Sign s    Exponent e    Mantissa m (= k)
23 // SF           1           8             16
24 // FF           1           8             23
25 // DF           1          11             52
26 // LF           1          32         intDsize*n >= 53
27
28
29 // Konversionen ohne Rundung:
30
31 // cl_SF_to_FF(x) wandelt ein Short-Float x in ein Single-Float um.
32 extern const cl_FF cl_SF_to_FF (const cl_SF& x);
33
34 // cl_SF_to_DF(x) wandelt ein Short-Float x in ein Double-Float um.
35 extern const cl_DF cl_SF_to_DF (const cl_SF& x);
36
37 // cl_SF_to_LF(x,len) wandelt ein Short-Float x in ein Long-Float mit len Digits um.
38 // > uintC len: gewünschte Anzahl Digits, >=LF_minlen
39 extern const cl_LF cl_SF_to_LF (const cl_SF& x, uintC len);
40
41 // cl_FF_to_DF(x) wandelt ein Single-Float x in ein Double-Float um.
42 extern const cl_DF cl_FF_to_DF (const cl_FF& x);
43
44 // cl_FF_to_LF(x,len) wandelt ein Single-Float x in ein Long-Float mit len Digits um.
45 // > uintC len: gewünschte Anzahl Digits, >=LF_minlen
46 extern const cl_LF cl_FF_to_LF (const cl_FF& x, uintC len);
47
48 // cl_DF_to_LF(x,len) wandelt ein Double-Float x in ein Long-Float mit len Digits um.
49 // > uintC len: gewünschte Anzahl Digits, >=LF_minlen
50 extern const cl_LF cl_DF_to_LF (const cl_DF& x, uintC len);
51
52
53 // Konversionen mit Rundung:
54
55 // cl_FF_to_SF(x) wandelt ein Single-Float x in ein Short-Float um.
56 extern const cl_SF cl_FF_to_SF (const cl_FF& x);
57
58 // cl_DF_to_SF(x) wandelt ein Double-Float x in ein Short-Float um.
59 extern const cl_SF cl_DF_to_SF (const cl_DF& x);
60
61 // cl_LF_to_SF(x) wandelt ein Long-Float x in ein Short-Float um.
62 extern const cl_SF cl_LF_to_SF (const cl_LF& x);
63
64 // cl_DF_to_FF(x) wandelt ein Double-Float x in ein Single-Float um.
65 extern const cl_FF cl_DF_to_FF (const cl_DF& x);
66
67 // cl_LF_to_FF(x) wandelt ein Long-Float x in ein Single-Float um.
68 extern const cl_FF cl_LF_to_FF (const cl_LF& x);
69
70 // cl_LF_to_DF(x) wandelt ein Long-Float x in ein Double-Float um.
71 extern const cl_DF cl_LF_to_DF (const cl_LF& x);
72
73
74 // Fehlermeldung wegen NaN
75 nonreturning_function(extern, cl_error_floating_point_nan, (void));
76
77
78 // Runtime typing support.
79 extern cl_class cl_class_ffloat;
80 extern cl_class cl_class_dfloat;
81 extern cl_class cl_class_lfloat;
82
83 // Type test.
84 inline cl_boolean longfloatp (const cl_F& x)
85 {
86         if (x.pointer_p())
87                 if (x.pointer_type() == &cl_class_lfloat)
88                         return cl_true;
89         return cl_false;
90 }
91
92 // Macro: verteilt je nach Float-Typ eines Floats x auf 4 Statements.
93 // floattypecase(x, SF_statement,FF_statement,DF_statement,LF_statement);
94 // x sollte eine Variable sein.
95 #ifdef CL_WIDE_POINTERS
96   #define floattypecase(x, SF_statement,FF_statement,DF_statement,LF_statement) \
97     if (!(x).pointer_p())                                               \
98       switch ((x).nonpointer_tag())                                     \
99         { case cl_SF_tag: { SF_statement } break;                       \
100           case cl_FF_tag: { FF_statement } break;                       \
101           default: NOTREACHED                                           \
102         }                                                               \
103       else {                                                            \
104         if ((x).pointer_type() == &cl_class_dfloat) { DF_statement }    \
105         else if ((x).pointer_type() == &cl_class_lfloat) { LF_statement } \
106         else NOTREACHED                                                 \
107       }
108 #else
109   #define floattypecase(x, SF_statement,FF_statement,DF_statement,LF_statement) \
110     if (!(x).pointer_p())                                               \
111       switch ((x).nonpointer_tag())                                     \
112         { case cl_SF_tag: { SF_statement } break;                       \
113           default: NOTREACHED                                           \
114         }                                                               \
115       else {                                                            \
116         if ((x).pointer_type() == &cl_class_ffloat) { FF_statement }    \
117         else if ((x).pointer_type() == &cl_class_dfloat) { DF_statement } \
118         else if ((x).pointer_type() == &cl_class_lfloat) { LF_statement } \
119         else NOTREACHED                                                 \
120       }
121 #endif
122
123 // Macro: verteilt je nach Float-Typ eines Floats x auf 4 Statements,
124 // die x vom jeweiligen Float-Typ benutzen dürfen.
125 // floatcase(x, SF_statement,FF_statement,DF_statement,LF_statement);
126 // x sollte eine Variable sein.
127   #define floatcase(x, SF_statement,FF_statement,DF_statement,LF_statement) \
128     floattypecase(x                                                        \
129       , var cl_SF& __tmp = *(cl_SF*)&x; var cl_SF& x = __tmp; SF_statement \
130       , var cl_FF& __tmp = *(cl_FF*)&x; var cl_FF& x = __tmp; FF_statement \
131       , var cl_DF& __tmp = *(cl_DF*)&x; var cl_DF& x = __tmp; DF_statement \
132       , var cl_LF& __tmp = *(cl_LF*)&x; var cl_LF& x = __tmp; LF_statement \
133       )
134
135
136 // GEN_F_OP1(arg1,F_OP,ergebnis_zuweisung)
137 // generates the body of a float operation with one argument.
138 // LF_OP is executed once the argument has been converted to its exact
139 // float type.
140 #define GEN_F_OP1(arg1,F_OP,ergebnis_zuweisung)  \
141 {                                                                       \
142         floatcase(arg1                                                  \
143         , /* SF */      ergebnis_zuweisung F_OP(arg1);                  \
144         , /* FF */      ergebnis_zuweisung F_OP(arg1);                  \
145         , /* DF */      ergebnis_zuweisung F_OP(arg1);                  \
146         , /* LF */      ergebnis_zuweisung F_OP(arg1);                  \
147         );                                                              \
148 }
149
150
151 // GEN_F_OP2(arg1,arg2,F_OP,r,s,ergebnis_zuweisung)
152 // generates the body of a float operation with two arguments.
153 // F_OP is executed once both arguments have been converted to the same
154 // float format (the longer one of arg1 and arg2). The r results are then
155 // converted the shorter of the two float formats. (r = 0,1,2.)
156 // s = 0,1. s=0 means the LF operation needs two long-floats of the same size.
157 // s=1 means they may be of different sizes.
158 #define GEN_F_OP2(arg1,arg2,F_OP,r,s,ergebnis_zuweisung)  \
159 {                                                                       \
160         floatcase(arg1                                                  \
161         , /* arg1 SF */                                                 \
162                 floatcase(arg2                                          \
163                 , /* arg2 SF */                                         \
164                         ergebnis_zuweisung CONCAT(NOMAP,r)(SF,          \
165                         F_OP(arg1,arg2) );                              \
166                 , /* arg2 FF */                                         \
167                         ergebnis_zuweisung CONCAT(MAP,r)(FF,cl_FF_to_SF,\
168                         F_OP(cl_SF_to_FF(arg1),arg2) );                 \
169                 , /* arg2 DF */                                         \
170                         ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_SF,\
171                         F_OP(cl_SF_to_DF(arg1),arg2) );                 \
172                 , /* arg2 LF */                                         \
173                         ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_SF,\
174                         F_OP(cl_SF_to_LF(arg1,CONCAT(LFlen,s)(arg2)),arg2) ); \
175                 );                                                      \
176         , /* arg1 FF */                                                 \
177                 floatcase(arg2                                          \
178                 , /* arg2 SF */                                         \
179                         ergebnis_zuweisung CONCAT(MAP,r)(FF,cl_FF_to_SF,\
180                         F_OP(arg1,cl_SF_to_FF(arg2)) );                 \
181                 , /* arg2 FF */                                         \
182                         ergebnis_zuweisung CONCAT(NOMAP,r)(FF,          \
183                         F_OP(arg1,arg2) );                              \
184                 , /* arg2 DF */                                         \
185                         ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_FF,\
186                         F_OP(cl_FF_to_DF(arg1),arg2) );                 \
187                 , /* arg2 LF */                                         \
188                         ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_FF,\
189                         F_OP(cl_FF_to_LF(arg1,CONCAT(LFlen,s)(arg2)),arg2) ); \
190                 );                                                      \
191         , /* arg1 DF */                                                 \
192                 floatcase(arg2                                          \
193                 , /* arg2 SF */                                         \
194                         ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_SF,\
195                         F_OP(arg1,cl_SF_to_DF(arg2)) );                 \
196                 , /* arg2 FF */                                         \
197                         ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_FF,\
198                         F_OP(arg1,cl_FF_to_DF(arg2)) );                 \
199                 , /* arg2 DF */                                         \
200                         ergebnis_zuweisung CONCAT(NOMAP,r)(DF,          \
201                         F_OP(arg1,arg2) );                              \
202                 , /* arg2 LF */                                         \
203                         ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_DF,\
204                         F_OP(cl_DF_to_LF(arg1,CONCAT(LFlen,s)(arg2)),arg2) ); \
205                 );                                                      \
206         , /* arg1 LF */                                                 \
207                 floatcase(arg2                                          \
208                 , /* arg2 SF */                                         \
209                         ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_SF,\
210                         F_OP(arg1,cl_SF_to_LF(arg2,CONCAT(LFlen,s)(arg1))) ); \
211                 , /* arg2 FF */                                         \
212                         ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_FF,\
213                         F_OP(arg1,cl_FF_to_LF(arg2,CONCAT(LFlen,s)(arg1))) ); \
214                 , /* arg2 DF */                                         \
215                         ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_DF,\
216                         F_OP(arg1,cl_DF_to_LF(arg2,CONCAT(LFlen,s)(arg1))) ); \
217                 , /* arg2 LF */                                         \
218                         GEN_LF_OP2_AUX(arg1,arg2,F_OP,r,s,ergebnis_zuweisung) \
219                 );                                                      \
220         );                                                              \
221 }
222 #define GEN_LF_OP2_AUX(arg1,arg2,F_OP,r,s,ergebnis_zuweisung)  \
223   CONCAT(GEN_LF_OP2_AUX,s)(arg1,arg2,F_OP,r,ergebnis_zuweisung)
224 #define GEN_LF_OP2_AUX0(arg1,arg2,F_OP,r,ergebnis_zuweisung)  \
225   var uintC len1 = TheLfloat(arg1)->len;                                \
226   var uintC len2 = TheLfloat(arg2)->len;                                \
227   if (len1 == len2) /* gleich -> direkt ausführen */                    \
228     { ergebnis_zuweisung CONCAT(NOMAP,r) (LF, F_OP(arg1,arg2)); }       \
229   elif (len1 > len2) /* -> arg2 auf die Länge von arg1 bringen */       \
230     { ergebnis_zuweisung CONCAT(MAP,r) (LF, LF_shorten_len2,            \
231       F_OP(arg1,extend(arg2,len1)) );                                   \
232     }                                                                   \
233   else /* (len1 < len2) -> arg1 auf die Länge von arg2 bringen */       \
234     { ergebnis_zuweisung CONCAT(MAP,r) (LF, LF_shorten_len1,            \
235       F_OP(extend(arg1,len2),arg2) );                                   \
236     }
237 #define LF_shorten_len1(arg)  shorten(arg,len1)
238 #define LF_shorten_len2(arg)  shorten(arg,len2)
239 #define GEN_LF_OP2_AUX1(arg1,arg2,F_OP,r,ergebnis_zuweisung)  \
240   ergebnis_zuweisung CONCAT(NOMAP,r) (LF, F_OP(arg1,arg2));
241
242 #define NOMAP0(F,EXPR)  EXPR
243 #define NOMAP1(F,EXPR)  EXPR
244 #define MAP0(F,FN,EXPR)  EXPR
245 #define MAP1(F,FN,EXPR)  FN(EXPR)
246
247 #define LFlen0(arg)  TheLfloat(arg)->len
248 #define LFlen1(arg)  LF_minlen
249
250
251 // cl_F_extendsqrt(x) erweitert die Genauigkeit eines Floats x um eine Stufe
252 // SF -> FF -> DF -> LF(4) -> LF(5) -> LF(6) -> ...
253 // Ein Float mit d Mantissenbits wird so zu einem Float mit
254 // mindestens d+sqrt(d)+2 Mantissenbits.
255 extern const cl_F cl_F_extendsqrt (const cl_F& x);
256
257 // cl_F_extendsqrtx(x) erweitert die Genauigkeit eines Floats x um eine Stufe
258 // SF -> FF -> DF -> LF(4) -> LF(5) -> LF(6) -> ...
259 // Ein Float mit d Mantissenbits und l Exponentenbits wird so zu einem Float
260 // mit mindestens d+sqrt(d)+2+(l-1) Mantissenbits.
261 extern const cl_F cl_F_extendsqrtx (const cl_F& x);
262
263 // cl_F_shortenrelative(x,y) tries to reduce the size of x, such that one
264 // wouldn't notice it when adding x to y. y must be /= 0. More precisely,
265 // this returns a float approximation of x, such that 1 ulp(x) < 1 ulp(y).
266 extern const cl_F cl_F_shortenrelative (const cl_F& x, const cl_F& y);
267
268
269 // Macro: dispatches according to a cl_float_format_t value.
270 // floatformatcase(value, SF_statement,FF_statement,DF_statement,LF_statement)
271 // LF_statement darf auf `len' zugreifen, die zu `value' korrespondierende
272 // Mantissenlänge (gemessen in Digits).
273   #define floatformatcase(value, SF_statement,FF_statement,DF_statement,LF_statement)  \
274     { if ((value) <= cl_float_format_sfloat) { SF_statement }           \
275       elif ((value) <= cl_float_format_ffloat) { FF_statement }         \
276       elif ((value) <= cl_float_format_dfloat) { DF_statement }         \
277       else { var uintL len = ceiling((uintL)(value),intDsize); LF_statement } \
278     }
279
280
281 #endif /* _CL_F_H */