// cl_F internals #ifndef _CL_F_H #define _CL_F_H #include "cl_number.h" #include "cl_macros.h" #include "cl_float.h" nonreturning_function(extern, cl_error_floating_point_overflow, (void)); nonreturning_function(extern, cl_error_floating_point_underflow, (void)); #define underflow_allowed() (! cl_inhibit_floating_point_underflow) // For all floating-point formats: // Sign s, Exponent e, Mantissa mk-1,...,m0 // represents the number (-1)^s * 2^(e-_EXP_MID) * [0 . 1 mk-1 ... m0] // e=0 represents the number 0, always with sign s=0 (and mantissa =0). // _exp_low and _exp_high are (inclusive) bounds for e. // Bits for Sign s Exponent e Mantissa m (= k) // SF 1 8 16 // FF 1 8 23 // DF 1 11 52 // LF 1 32 intDsize*n >= 53 // Konversionen ohne Rundung: // cl_SF_to_FF(x) wandelt ein Short-Float x in ein Single-Float um. extern const cl_FF cl_SF_to_FF (const cl_SF& x); // cl_SF_to_DF(x) wandelt ein Short-Float x in ein Double-Float um. extern const cl_DF cl_SF_to_DF (const cl_SF& x); // cl_SF_to_LF(x,len) wandelt ein Short-Float x in ein Long-Float mit len Digits um. // > uintC len: gewünschte Anzahl Digits, >=LF_minlen extern const cl_LF cl_SF_to_LF (const cl_SF& x, uintC len); // cl_FF_to_DF(x) wandelt ein Single-Float x in ein Double-Float um. extern const cl_DF cl_FF_to_DF (const cl_FF& x); // cl_FF_to_LF(x,len) wandelt ein Single-Float x in ein Long-Float mit len Digits um. // > uintC len: gewünschte Anzahl Digits, >=LF_minlen extern const cl_LF cl_FF_to_LF (const cl_FF& x, uintC len); // cl_DF_to_LF(x,len) wandelt ein Double-Float x in ein Long-Float mit len Digits um. // > uintC len: gewünschte Anzahl Digits, >=LF_minlen extern const cl_LF cl_DF_to_LF (const cl_DF& x, uintC len); // Konversionen mit Rundung: // cl_FF_to_SF(x) wandelt ein Single-Float x in ein Short-Float um. extern const cl_SF cl_FF_to_SF (const cl_FF& x); // cl_DF_to_SF(x) wandelt ein Double-Float x in ein Short-Float um. extern const cl_SF cl_DF_to_SF (const cl_DF& x); // cl_LF_to_SF(x) wandelt ein Long-Float x in ein Short-Float um. extern const cl_SF cl_LF_to_SF (const cl_LF& x); // cl_DF_to_FF(x) wandelt ein Double-Float x in ein Single-Float um. extern const cl_FF cl_DF_to_FF (const cl_DF& x); // cl_LF_to_FF(x) wandelt ein Long-Float x in ein Single-Float um. extern const cl_FF cl_LF_to_FF (const cl_LF& x); // cl_LF_to_DF(x) wandelt ein Long-Float x in ein Double-Float um. extern const cl_DF cl_LF_to_DF (const cl_LF& x); // Fehlermeldung wegen NaN nonreturning_function(extern, cl_error_floating_point_nan, (void)); // Runtime typing support. extern cl_class cl_class_ffloat; extern cl_class cl_class_dfloat; extern cl_class cl_class_lfloat; // Type test. inline cl_boolean longfloatp (const cl_F& x) { if (x.pointer_p()) if (x.pointer_type() == &cl_class_lfloat) return cl_true; return cl_false; } // Macro: verteilt je nach Float-Typ eines Floats x auf 4 Statements. // floattypecase(x, SF_statement,FF_statement,DF_statement,LF_statement); // x sollte eine Variable sein. #ifdef CL_WIDE_POINTERS #define floattypecase(x, SF_statement,FF_statement,DF_statement,LF_statement) \ if (!(x).pointer_p()) \ switch ((x).nonpointer_tag()) \ { case cl_SF_tag: { SF_statement } break; \ case cl_FF_tag: { FF_statement } break; \ default: NOTREACHED \ } \ else { \ if ((x).pointer_type() == &cl_class_dfloat) { DF_statement } \ else if ((x).pointer_type() == &cl_class_lfloat) { LF_statement } \ else NOTREACHED \ } #else #define floattypecase(x, SF_statement,FF_statement,DF_statement,LF_statement) \ if (!(x).pointer_p()) \ switch ((x).nonpointer_tag()) \ { case cl_SF_tag: { SF_statement } break; \ default: NOTREACHED \ } \ else { \ if ((x).pointer_type() == &cl_class_ffloat) { FF_statement } \ else if ((x).pointer_type() == &cl_class_dfloat) { DF_statement } \ else if ((x).pointer_type() == &cl_class_lfloat) { LF_statement } \ else NOTREACHED \ } #endif // Macro: verteilt je nach Float-Typ eines Floats x auf 4 Statements, // die x vom jeweiligen Float-Typ benutzen dürfen. // floatcase(x, SF_statement,FF_statement,DF_statement,LF_statement); // x sollte eine Variable sein. #define floatcase(x, SF_statement,FF_statement,DF_statement,LF_statement) \ floattypecase(x \ , var cl_SF& __tmp = *(cl_SF*)&x; var cl_SF& x = __tmp; SF_statement \ , var cl_FF& __tmp = *(cl_FF*)&x; var cl_FF& x = __tmp; FF_statement \ , var cl_DF& __tmp = *(cl_DF*)&x; var cl_DF& x = __tmp; DF_statement \ , var cl_LF& __tmp = *(cl_LF*)&x; var cl_LF& x = __tmp; LF_statement \ ) // GEN_F_OP1(arg1,F_OP,ergebnis_zuweisung) // generates the body of a float operation with one argument. // LF_OP is executed once the argument has been converted to its exact // float type. #define GEN_F_OP1(arg1,F_OP,ergebnis_zuweisung) \ { \ floatcase(arg1 \ , /* SF */ ergebnis_zuweisung F_OP(arg1); \ , /* FF */ ergebnis_zuweisung F_OP(arg1); \ , /* DF */ ergebnis_zuweisung F_OP(arg1); \ , /* LF */ ergebnis_zuweisung F_OP(arg1); \ ); \ } // GEN_F_OP2(arg1,arg2,F_OP,r,s,ergebnis_zuweisung) // generates the body of a float operation with two arguments. // F_OP is executed once both arguments have been converted to the same // float format (the longer one of arg1 and arg2). The r results are then // converted the shorter of the two float formats. (r = 0,1,2.) // s = 0,1. s=0 means the LF operation needs two long-floats of the same size. // s=1 means they may be of different sizes. #define GEN_F_OP2(arg1,arg2,F_OP,r,s,ergebnis_zuweisung) \ { \ floatcase(arg1 \ , /* arg1 SF */ \ floatcase(arg2 \ , /* arg2 SF */ \ ergebnis_zuweisung CONCAT(NOMAP,r)(SF, \ F_OP(arg1,arg2) ); \ , /* arg2 FF */ \ ergebnis_zuweisung CONCAT(MAP,r)(FF,cl_FF_to_SF,\ F_OP(cl_SF_to_FF(arg1),arg2) ); \ , /* arg2 DF */ \ ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_SF,\ F_OP(cl_SF_to_DF(arg1),arg2) ); \ , /* arg2 LF */ \ ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_SF,\ F_OP(cl_SF_to_LF(arg1,CONCAT(LFlen,s)(arg2)),arg2) ); \ ); \ , /* arg1 FF */ \ floatcase(arg2 \ , /* arg2 SF */ \ ergebnis_zuweisung CONCAT(MAP,r)(FF,cl_FF_to_SF,\ F_OP(arg1,cl_SF_to_FF(arg2)) ); \ , /* arg2 FF */ \ ergebnis_zuweisung CONCAT(NOMAP,r)(FF, \ F_OP(arg1,arg2) ); \ , /* arg2 DF */ \ ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_FF,\ F_OP(cl_FF_to_DF(arg1),arg2) ); \ , /* arg2 LF */ \ ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_FF,\ F_OP(cl_FF_to_LF(arg1,CONCAT(LFlen,s)(arg2)),arg2) ); \ ); \ , /* arg1 DF */ \ floatcase(arg2 \ , /* arg2 SF */ \ ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_SF,\ F_OP(arg1,cl_SF_to_DF(arg2)) ); \ , /* arg2 FF */ \ ergebnis_zuweisung CONCAT(MAP,r)(DF,cl_DF_to_FF,\ F_OP(arg1,cl_FF_to_DF(arg2)) ); \ , /* arg2 DF */ \ ergebnis_zuweisung CONCAT(NOMAP,r)(DF, \ F_OP(arg1,arg2) ); \ , /* arg2 LF */ \ ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_DF,\ F_OP(cl_DF_to_LF(arg1,CONCAT(LFlen,s)(arg2)),arg2) ); \ ); \ , /* arg1 LF */ \ floatcase(arg2 \ , /* arg2 SF */ \ ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_SF,\ F_OP(arg1,cl_SF_to_LF(arg2,CONCAT(LFlen,s)(arg1))) ); \ , /* arg2 FF */ \ ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_FF,\ F_OP(arg1,cl_FF_to_LF(arg2,CONCAT(LFlen,s)(arg1))) ); \ , /* arg2 DF */ \ ergebnis_zuweisung CONCAT(MAP,r)(LF,cl_LF_to_DF,\ F_OP(arg1,cl_DF_to_LF(arg2,CONCAT(LFlen,s)(arg1))) ); \ , /* arg2 LF */ \ GEN_LF_OP2_AUX(arg1,arg2,F_OP,r,s,ergebnis_zuweisung) \ ); \ ); \ } #define GEN_LF_OP2_AUX(arg1,arg2,F_OP,r,s,ergebnis_zuweisung) \ CONCAT(GEN_LF_OP2_AUX,s)(arg1,arg2,F_OP,r,ergebnis_zuweisung) #define GEN_LF_OP2_AUX0(arg1,arg2,F_OP,r,ergebnis_zuweisung) \ var uintC len1 = TheLfloat(arg1)->len; \ var uintC len2 = TheLfloat(arg2)->len; \ if (len1 == len2) /* gleich -> direkt ausführen */ \ { ergebnis_zuweisung CONCAT(NOMAP,r) (LF, F_OP(arg1,arg2)); } \ elif (len1 > len2) /* -> arg2 auf die Länge von arg1 bringen */ \ { ergebnis_zuweisung CONCAT(MAP,r) (LF, LF_shorten_len2, \ F_OP(arg1,extend(arg2,len1)) ); \ } \ else /* (len1 < len2) -> arg1 auf die Länge von arg2 bringen */ \ { ergebnis_zuweisung CONCAT(MAP,r) (LF, LF_shorten_len1, \ F_OP(extend(arg1,len2),arg2) ); \ } #define LF_shorten_len1(arg) shorten(arg,len1) #define LF_shorten_len2(arg) shorten(arg,len2) #define GEN_LF_OP2_AUX1(arg1,arg2,F_OP,r,ergebnis_zuweisung) \ ergebnis_zuweisung CONCAT(NOMAP,r) (LF, F_OP(arg1,arg2)); #define NOMAP0(F,EXPR) EXPR #define NOMAP1(F,EXPR) EXPR #define MAP0(F,FN,EXPR) EXPR #define MAP1(F,FN,EXPR) FN(EXPR) #define LFlen0(arg) TheLfloat(arg)->len #define LFlen1(arg) LF_minlen // cl_F_extendsqrt(x) erweitert die Genauigkeit eines Floats x um eine Stufe // SF -> FF -> DF -> LF(4) -> LF(5) -> LF(6) -> ... // Ein Float mit d Mantissenbits wird so zu einem Float mit // mindestens d+sqrt(d)+2 Mantissenbits. extern const cl_F cl_F_extendsqrt (const cl_F& x); // cl_F_extendsqrtx(x) erweitert die Genauigkeit eines Floats x um eine Stufe // SF -> FF -> DF -> LF(4) -> LF(5) -> LF(6) -> ... // Ein Float mit d Mantissenbits und l Exponentenbits wird so zu einem Float // mit mindestens d+sqrt(d)+2+(l-1) Mantissenbits. extern const cl_F cl_F_extendsqrtx (const cl_F& x); // cl_F_shortenrelative(x,y) tries to reduce the size of x, such that one // wouldn't notice it when adding x to y. y must be /= 0. More precisely, // this returns a float approximation of x, such that 1 ulp(x) < 1 ulp(y). extern const cl_F cl_F_shortenrelative (const cl_F& x, const cl_F& y); // Macro: dispatches according to a cl_float_format_t value. // floatformatcase(value, SF_statement,FF_statement,DF_statement,LF_statement) // LF_statement darf auf `len' zugreifen, die zu `value' korrespondierende // Mantissenlänge (gemessen in Digits). #define floatformatcase(value, SF_statement,FF_statement,DF_statement,LF_statement) \ { if ((value) <= cl_float_format_sfloat) { SF_statement } \ elif ((value) <= cl_float_format_ffloat) { FF_statement } \ elif ((value) <= cl_float_format_dfloat) { DF_statement } \ else { var uintL len = ceiling((uintL)(value),intDsize); LF_statement } \ } #endif /* _CL_F_H */