Fixed floating point minimum values, must be -*_MAX, not *_MIN !
[libfirm] / ir / tv / fltcalc.c
1 /* fltcalc.c
2  * Authors: Matthias Heil
3  */
4
5 /*
6  * TODO:
7  *
8  * This code uses the C-type LLDBL to respesent floating
9  * point values. This is bad because:
10  *
11  * 1.) It depends on IEEE arithmetic on the compilation engine (hardly a problem)
12  * 2.) The existance on the type and its bits size (may be identical to double or even float)
13  * 3.) Arithmetic operations will be done with "higher order" precision, which might be wrong
14  *
15  * Replace this code ASAP.
16  */
17 #include "fltcalc.h"
18 #include <string.h>
19 #include <float.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 #ifdef USE_LONG_DOUBLE
24 /* have long double type */
25
26 /* only defined in C99 mode */
27 extern long double strtold(const char *str, char **end);
28
29 #define strtoLLD        strtold
30
31 #else
32 /* don't have long double type */
33
34 extern double strtod(const char *str, char **end);
35
36 #define strtoLLD        strtod
37
38 #endif
39
40 /********
41  * globals
42  ********/
43 static LLDBL value;
44
45 #define CAST_IN(val) (*((LLDBL *)((val))))
46 #define CAST_OUT(val) ((void *)&(val))
47
48 #define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(LLDBL))
49 /********
50  * private functions
51  ********/
52
53 /********
54  * functions defined in fltcalc.h
55  ********/
56 const void *fc_get_buffer(void)
57 {
58   return CAST_OUT(value);
59 }
60
61 const int fc_get_buffer_length(void)
62 {
63   return sizeof(LLDBL);
64 }
65
66 void fc_val_from_str(const char *str, unsigned int len)
67 {
68   CLEAR_BUFFER();
69   value = strtoLLD(str, NULL);
70 }
71
72 void fc_val_from_float(LLDBL l)
73 {
74   CLEAR_BUFFER();
75   value = l;
76 }
77
78 LLDBL fc_val_to_float(const void *val)
79 {
80   return CAST_IN(val);
81 }
82
83 void fc_get_min(unsigned int num_bits)
84 {
85   CLEAR_BUFFER();
86
87   /*
88    * Beware: FLT_MIN is the "Minimum normalised float",
89    * not the smallest number in arithmetic sense
90    */
91   switch (num_bits) {
92     case 32:
93       value = -FLT_MAX;
94       break;
95     case 64:
96       value = -DBL_MAX;
97       break;
98     case 80:
99     default:
100       value = -LDBL_MAX;
101       break;
102   }
103 }
104
105 void fc_get_max(unsigned int num_bits)
106 {
107   CLEAR_BUFFER();
108   switch (num_bits)
109   {
110     case 32:
111       value = FLT_MAX;
112       break;
113     case 64:
114       value = DBL_MAX;
115       break;
116     case 80:
117     default:
118       value = LDBL_MAX;
119       break;
120   }
121 }
122
123 void fc_get_nan(void)
124 {
125   value = strtoLLD("nan", NULL);
126
127 }
128
129 void fc_get_inf(void)
130 {
131   value = strtoLLD("inf", NULL);
132 }
133
134 void fc_calc(const void *a, const void *b, int opcode)
135 {
136   CLEAR_BUFFER();
137   switch (opcode)
138   {
139     case FC_ADD:
140       value = CAST_IN(a) + CAST_IN(b);
141       break;
142     case FC_SUB:
143       value = CAST_IN(a) - CAST_IN(b);
144       break;
145     case FC_MUL:
146       value = CAST_IN(a) * CAST_IN(b);
147       break;
148     case FC_DIV:
149       value = CAST_IN(a) / CAST_IN(b);
150       break;
151     case FC_NEG:
152       value = -CAST_IN(a);
153       break;
154   }
155 }
156
157 int fc_comp(const void *a, const void *b)
158 {
159   char buf1[40], buf2[40];
160
161   if (CAST_IN(a) == CAST_IN(b)) {
162     return 0;
163   }
164   else if (CAST_IN(a) > CAST_IN(b)) {
165     return 1;
166   }
167   else {
168     return -1;
169   }
170 }
171
172 char *fc_print_dec(const void *a, char *buf, int buflen)
173 {
174 #ifdef USE_LONG_DOUBLE
175   snprintf(buf, buflen, "%1.30Lg", CAST_IN(a));
176 #else
177   snprintf(buf, buflen, "%1.30g", CAST_IN(a));
178 #endif
179   return buf;
180 }
181
182 unsigned char fc_sub_bits(const void *value, unsigned num_bits, unsigned byte_ofs)
183 {
184   LLDBL val = CAST_IN(value);
185   float f;
186   double d;
187
188   unsigned char *p;
189   unsigned len;
190
191   switch (num_bits) {
192   case 32:
193     f = (float)val;
194     p = (unsigned char *)&f;
195     len = 4;
196     break;
197
198   case 64:
199     d = (double)val;
200     p = (unsigned char *)&d;
201     len = 8;
202     break;
203
204   case 80:
205     p = (unsigned char *)&val;
206     len = 10;
207     break;
208
209   default:
210     return 0;
211   }
212
213   if (byte_ofs > len)
214     return 0;
215   return p[byte_ofs];
216 }