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