]> www.ginac.de Git - cln.git/blob - src/real/format-output/cl_fmt_scaleexp.cc
8d4af32d0c23f85bc76daa563a6f1e3223014ef6
[cln.git] / src / real / format-output / cl_fmt_scaleexp.cc
1 // format_scale_exponent().
2
3 // General includes.
4 #include "cl_sysdep.h"
5
6 CL_PROVIDE(cl_fmt_scaleexp)
7
8 // Specification.
9 #include "cl_format.h"
10
11
12 // Implementation.
13
14 #include "cl_real.h"
15 #include "cl_integer.h"
16 #include "cl_float.h"
17 #include "cl_F.h"
18 #include "cl_SF.h"
19 #include "cl_FF.h"
20 #include "cl_DF.h"
21 #include "cl_LF.h"
22
23 // NOTE: This may introduce roundoff-errors, through the use of *, /, expt.
24 // But this doesn't matter since format_float_to_string() works with
25 // exact integers, starting with integer_decode_float().
26
27 // For a floating point format f, five characteristic numbers:
28 struct float_format_params {
29         cl_F zero;      // cl_float(0,f)
30         cl_F one;       // cl_float(1,f)
31         cl_F ten;       // cl_float(10,f)
32         cl_F tenth;     // cl_float(1/10,f)
33         cl_F lg2;       // log(10,2), as needed (max. 32 bits)
34 // Constructor:
35         float_format_params (cl_F a, cl_F b, cl_F c, cl_F d, cl_F e)
36                 : zero(a), one(b), ten(c), tenth(d), lg2(e) {}
37 };
38
39 static const cl_RA tenth = (cl_RA)"1/10";
40 static const cl_SF SF_zero = cl_RA_to_SF(0);
41 static const cl_SF SF_one = cl_RA_to_SF(1);
42 static const cl_SF SF_ten = cl_RA_to_SF(10);
43 static const cl_SF SF_tenth = cl_RA_to_SF(tenth);
44 static const cl_FF FF_zero = cl_RA_to_FF(0);
45 static const cl_FF FF_one = cl_RA_to_FF(1);
46 static const cl_FF FF_ten = cl_RA_to_FF(10);
47 static const cl_FF FF_tenth = cl_RA_to_FF(tenth);
48 static const cl_DF DF_zero = cl_RA_to_DF(0);
49 static const cl_DF DF_one = cl_RA_to_DF(1);
50 static const cl_DF DF_ten = cl_RA_to_DF(10);
51 static const cl_DF DF_tenth = cl_RA_to_DF(tenth);
52 static const cl_SF SF_lg2 = (cl_SF)"0.30103";
53 static const cl_DF DF_lg2 = (cl_DF)"0.30102999566";
54
55 static const float_format_params get_float_params (const cl_F& arg)
56 {
57         floattypecase(arg
58         ,       return float_format_params(SF_zero,SF_one,SF_ten,SF_tenth,SF_lg2);
59         ,       return float_format_params(FF_zero,FF_one,FF_ten,FF_tenth,SF_lg2);
60         ,       return float_format_params(DF_zero,DF_one,DF_ten,DF_tenth,SF_lg2);
61         ,       var uintC len = TheLfloat(arg)->len;
62                 return float_format_params(
63                         cl_I_to_LF(0,len),
64                         cl_I_to_LF(1,len),
65                         cl_I_to_LF(10,len),
66                         cl_RA_to_LF(tenth,len),
67                         DF_lg2 // lg2 wird mit 32 Bit Genauigkeit gebraucht
68                        );
69         );
70 }
71
72 const cl_decoded_float format_scale_exponent (const cl_F& arg)
73 {
74         // Get float format parameters.
75         var const float_format_params params = get_float_params(arg);
76         var const cl_F& zero = params.zero;
77         var const cl_F& one = params.one;
78         var const cl_F& ten = params.ten;
79         var const cl_F& tenth = params.tenth;
80         var const cl_F& lg2 = params.lg2;
81         // Decode arg.
82         if (zerop(arg))
83                 return cl_decoded_float(zero,0,one);
84         var cl_F abs_arg = abs(arg);
85         var cl_decoded_float decoded = decode_float(abs_arg);
86         var cl_I& expon = decoded.exponent;
87         var cl_I expon10a = truncate1(expon*lg2); // nicht round, um Überlauf zu vermeiden
88         var cl_F signif10a = abs_arg / expt(ten,expon10a);
89         // Maybe need to increment expon10.
90         var cl_I expon10b = expon10a;
91         var cl_F signif10b = signif10a;
92         {
93                 var cl_F tenpow = ten;
94                 until (signif10b < one) {
95                         expon10b = expon10b + 1;
96                         signif10b = signif10a / tenpow;
97                         tenpow = tenpow * ten;
98                 }
99         }
100         // Maybe need to decrement expon10.
101         var cl_I expon10c = expon10b;
102         var cl_F signif10c = signif10b;
103         {
104                 var cl_F tenpow = ten;
105                 until (signif10c >= tenth) {
106                         expon10c = expon10c - 1;
107                         signif10c = signif10b * tenpow;
108                         tenpow = tenpow * ten;
109                 }
110         }
111         return cl_decoded_float(signif10c,expon10c,float_sign(arg));
112 }
113
114 CL_PROVIDE_END(cl_fmt_scaleexp)